提问者:小点点

Spring 3.2:无法将@Service注释bean自动连接到@Bean注释bean-发生BeanNotFoundException


我不想在这里问一个问题,但是我已经看了20多个关于堆栈溢出的其他类似问题,它们似乎都不是完全相同的场景!

我有一个@Service注解bean(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注释bean(Service3.java)中完全可以正常工作,所以我知道bean正在初始化。例如。

Service3.java

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

有人能在这里看到任何明显的东西吗?不幸的是,我们混合了XML和基于注释的bean实例化(尝试移动到注释是一个缓慢的过程,因为我们仍然在Spring 3.2上!),所以组件扫描等是在XML上下文文件中完成的。

有趣的是,当我尝试调试这种情况时,我打印出了在设置应用程序上下文时初始化的Spring bean列表,然后在加载Web应用程序的登陆页面时(当然是在Service2中注释掉Service1的自动装配之后),而@Service注释bean只出现在后一个列表中。那么这是否意味着我的问题是@Service注释bean总是在@Bean注释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初始化为@Bean注释bean时,自动装配实际上是有效的,就像Service2.java一样。

非常感谢提前!


共1个答案

匿名用户

在您的情况下,问题是使用Class. forName加载和实例化服务对象。在这种情况下,自动装配功能将不起作用,因为它不是由Spring Application上下文实例化的。您需要使用以下代码手动自动装配。

@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;
    }
}