Spring Java 配置相同的 Bean 引用

Spring Java config same Bean reference

查看问题我有一个问题。

@Configuration
public class Config {

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

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

}

Spring 如何保证方法 randomBean() 将 return 与注入 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 主题中描述了这种行为。

根据 Spring 文档,只有在 @Configuration 中声明了 @Bean 方法时,才可能进行 bean 间注入。它使用 CGLIB,所有 @Configuration 类 都是它的子类。

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

只有一个"randomBean"因为默认作用域是"singleton".(为了强制Spring每次产生一个新的bean实例需要时,您应该将 bean 的范围属性声明为原型)

singleton

This scopes the bean definition to a single instance per Spring IoC container (default).

prototype

This scopes a single bean definition to have any number of object instances.

Spring 保证方法 randomBean() 将 return 与使用 proxies.[= 注入 AnotherBean 的引用相同16=]

为了生成代理,Spring 使用名为 CGLIB.

的第三方库
  1. Spring 通过生成一个 CGLIB 子类来增强 类 与 Spring 容器交互以遵守 bean 范围 方法的语义。

  2. 每个这样的bean方法都会在生成的子类中被覆盖, 仅委托给实际的 bean 方法实现,如果 容器实际上请求构造一个新实例。

  3. 否则,对这样的bean方法的调用作为返回引用 到容器中,通过名称获取对应的bean。

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
   }

}