Spring 3.2: Невозможно автоматически передать аннотированный компонент @Service в аннотированный компонент @Bean - возникновение исключения BeanNotFoundException - PullRequest
2 голосов
/ 13 марта 2020

Я не хотел задавать здесь вопрос, но я рассмотрел более 20 подобных проблем с переполнением стека, и ни один из них не выглядит точно таким же сценарием!

У меня есть @ Service аннотированный компонент ( Service1. java), который я пытаюсь автоматически передать в другой сервис ( Service2. java) - проблема в том, что Service2 аннотируется аннотацией @ Bean , а не аннотацией @ Service , поскольку подкласс, который создается, может изменяться в зависимости от определенной базы данных конфигурации. Вот соответствующий код:

ApplicationConfig. java

@Configuration
public class ApplicationConfig {

    @Bean
    public Service2 service2() throws Exception {
        String className = Config.getString("service2.class");
        return (Service2) Class.forName(className).newInstance();
    }
}

Service1. java

@Service
public class Service1 {
    ....
}

Service2. java

public class Service2 {
    private @Autowired Service1 service1;
    ...
}

Интересно, что автоматическое подключение Service1 к другому @ Service аннотированному компоненту ( Service3. java) работает отлично, поэтому я знаю, что bean-компонент инициализируется нормально. Например,

Service3. java

@Service
public class Service3 {
    private @Autowired Service1 service1;
}

Кто-нибудь может увидеть здесь что-нибудь очевидное? К сожалению, у нас есть смесь XML и экземпляров bean-компонентов на основе аннотаций (попытка перейти к аннотациям - это медленный процесс, так как мы все еще на Spring 3.2!), Поэтому сканирование компонентов и т. Д. c выполняется в XML файл контекста.

Интересно, что при попытке отладить ситуацию я распечатал список бинов Spring, инициализированных в момент установки контекста приложения, а затем при загрузке целевой страницы веб-приложения (после комментирования автопроводки). Service1 в Service2 и, конечно, аннотированные компоненты @ Service появились только в последнем списке. Значит ли это, что моя проблема в том, что аннотированные компоненты @ Service всегда инициализируются после аннотированных компонентов @ Bean , поэтому я получаю свое исключение при запуске? Вот исключение для полноты:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.eo3.eo3app.spring3.util.Service1] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Пожалуйста, дайте мне знать, если мне нужно добавить какие-либо другие детали. Очевидно, я хотел бы иметь возможность аннотировать все свои классы обслуживания с помощью аннотации @ Service , но не знаю, как это сделать в сценарии, где возвращаемый подкласс может отличаться при каждом запуске приложения. вверх (как с Service2. java).

Я почти забыл упомянуть, что автопроводка действительно работала, когда я изменил Service1. java с @ Service аннотированный бин для инициализации его как @ Bean аннотированный бин, такой же как Service2. java.

Большое спасибо заранее !

1 Ответ

1 голос
/ 13 марта 2020

Проблема в вашем случае заключается в использовании Class.forName для загрузки и создания экземпляра объекта службы. В этом случае возможности Autowiring не будут работать, так как они не создаются в контексте приложения Spring. Вам нужно вручную выполнить автоматическое подключение, используя следующий код.

@Configuration
public class ApplicationConfig {

    @Bean
    public Service2 service2(ApplicationContext applicationContext) throws Exception {
        String className = Config.getString("service2.class");
        Service2 service2Impl = (Service2) Class.forName(className).newInstance();

        applicationContext.getAutowireCapableBeanFactory().autowireBean(service2Impl);

        return service2Impl;
    }
}
...