Spring Java配置相同的Bean引用

时间:2017-06-13 09:07:18

标签: java spring spring-java-config

回顾问题Autowire a bean within Spring's Java configuration我有一个问题。

@Configuration
public class Config {

   @Bean
   public RandomBean randomBean(){
       return new RandomBean();
   }

   @Bean
   public AnotherBean anotherBean(){
       return new AnotherBean(randomBean()); // this line
   }

}

Spring如何保证方法randomBean()将返回与注入AnotherBean的方法相同的引用?

是通过代理实现的吗?

另一方面,以提供依赖关系作为方法参数来做这件事显而易见:

@Configuration
public class Config {

   @Bean
   public RandomBean randomBean(){
       return new RandomBean();
   }

   @Bean
   public AnotherBean anotherBean(RandomBean randomBean){
       return new AnotherBean(randomBean);
   }

}

编辑最后,我发现了Further information about how Java-based configuration works internally主题中描述的这种行为。

2 个答案:

答案 0 :(得分:7)

只有一个" randomBean"因为默认范围是" singleton" 。(为了在每次需要时强制Spring生成一个新的bean实例,你应该声明bean的scope属性是原型)

  

<强>单

     

这将bean定义范围限定为每个Spring IoC的单个实例   容器(默认)。

     

<强>原型

     

这使单个bean定义的范围包含任意数量的对象   实例

Spring保证方法randomBean()将返回与注入AnotherBean的引用相同的引用使用代理

为了生成代理,Spring使用名为 CGLIB 的第三方库。

  1. Spring通过生成 CGLIB 子类来增强类 与Spring容器交互以尊重bean的范围 方法的语义。

  2. 每个这样的bean方法都将在生成的子类中重写,     如果是,只委托给实际的bean方法实现     容器实际上请求新实例的构造

  3. 否则,对这种bean方法的调用将作为参考     到容器,按名称获取相应的bean。

  4. 请参阅org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor

    // To handle the case of an inter-bean method reference, we must explicitly check the
    // container for already cached instances.
    
    // First, check to see if the requested bean is a FactoryBean. If so, create a subclass
    // proxy that intercepts calls to getObject() and returns any cached bean instance.
    // This ensures that the semantics of calling a FactoryBean from within @Bean methods
    // is the same as that of referring to a FactoryBean within XML. See SPR-6602.
    if (factoryContainsBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName) && factoryContainsBean(beanName)) {
        Object factoryBean = this.beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
        if (factoryBean instanceof ScopedProxyFactoryBean) {
            // Pass through - scoped proxy factory beans are a special case and should not
            // be further proxied
        }
        else {
            // It is a candidate FactoryBean - go ahead with enhancement
            return enhanceFactoryBean(factoryBean.getClass(), beanName);
        }
    }
    

    如果您想获得两个不同的bean,则应该通过@Scope

    更改默认范围
    @Configuration
    public class Config {
    
       @Bean
       @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
       public RandomBean randomBean(){
           return new RandomBean();
       }
    
       @Bean
       public AnotherBean anotherBean(){
           return new AnotherBean(randomBean()); // this line
       }
    
    }
    

答案 1 :(得分:1)

根据Spring文档,只有在@Bean内声明@Configuration方法时才可能注入bean。它使用CGLIB,所有@Configuration类都由它子类化。

请检查此参考https://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-java-bean-annotation,“7.12.4使用@Configuration注释”部分。您可以从原始来源找到您的问题的答案。