Spring Javaconfig bean间依赖关系

时间:2014-09-19 22:14:55

标签: spring dependency-injection spring-boot spring-java-config

浏览Spring Javaconfig参考文档 http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html 我发现了一些令人困惑的部分......

" 5.12.4使用@Configuration注释" 下,它说:

"当@Beans彼此依赖时,表达该依赖关系就像让一个bean方法调用另一个一样简单:

@Configuration
public class AppConfig {
    @Bean
    public Foo foo() {
        return new Foo(bar());
    }
    @Bean
    public Bar bar() {
        return new Bar();
    }
}

在上面的例子中,foo bean通过构造函数注入接收对bar的引用。"

好吧,如果一切都是无状态的,那可能并不重要,但如果你有上面的配置,然后在你的应用程序中做:

@Autowired 
private Foo foo;

@Autowired 
private Bar bar;

检查bean的hashCodes,结果是,您的私有变量 bar 将引用 Bar 不同实例而不是一个由 foo 使用的, 这可能不是你所期望的,对吗?

我想说正常模式应该是:

@Configuration
public class AppConfig {
    @Bean
    public Bar bar() {
        return new Bar();
    }
    @Autowired Bar bar;
    @Bean
    public Foo foo() {
        return new Foo(bar);
    }
}

现在,当您在应用中自动装配两个bean时,您只会创建一个Bar实例。

我是否遗漏了某些内容,或者我是否认为文档存在缺陷?

然后,再进一步,在 &#34部分下;有关基于Java的配置如何在内部工作的更多信息" 看起来他们试图澄清"这个问题:

@Configuration
public class AppConfig {
    @Bean
    public ClientService clientService1() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }
    @Bean
    public ClientService clientService2() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }
    @Bean
    public ClientDao clientDao() {
        return new ClientDaoImpl();
    }
}

现在,不幸的是,这个配置甚至不能在运行时加载,因为有两个相同类型的bean,ClientService,没有区别属性,所以得到异常

org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
No qualifying bean of type [.....] is defined: 
expected single matching bean but found 2

但是即使我们稍微改变了这个例子,并给出了前两个bean不同的类型,

@Bean
public ClientService1 clientService1() {...clientDao()...}
@Bean
public ClientService2 clientService2() {...clientDao()...}
@Bean
public ClientDao clientDao() {
    return new ClientDaoImpl();
}

这仍然是不正确的,因为 - 与文本声称的相反 - 我们仍然会创建3个不同的ClientDaoImpl实例, 当自动装配所有3个豆时。

再次,我完全错过了什么,或者文档真的像我看来一样糟糕?

编辑:添加了一个演示,演示了我看到的问题:

https://github.com/rop49/demo

bean ServiceA , 和两个bean ServiceB1 ServiceB2 构造函数注入 ServiceA

然后两个测试类 Config01Test Config02Test 除配置外完全相同。第一次测试PASSES,第二次失败是因为唯一性 - 断言。

2 个答案:

答案 0 :(得分:8)

检查配置类上是否有@Configuration注释。至少在Config01Config02类中缺少您的演示。如果我将它们添加到这些类中,测试就会通过。

答案 1 :(得分:0)

我自己没有测试这个例子,这应该确保你在整个应用程序上下文中只有一个Bar实例

@Configuration
public class AppConfig {
    @Bean
    public Foo foo(Bar bar) {
        return new Foo(bar);
    }
    @Bean
    public Bar bar() {
        return new Bar();
    }
}