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.
的第三方库
Spring 通过生成一个 CGLIB 子类来增强 类
与 Spring 容器交互以遵守 bean 范围
方法的语义。
每个这样的bean方法都会在生成的子类中被覆盖,
仅委托给实际的 bean 方法实现,如果
容器实际上请求构造一个新实例。
否则,对这样的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
}
}
查看问题
@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.
的第三方库Spring 通过生成一个 CGLIB 子类来增强 类 与 Spring 容器交互以遵守 bean 范围 方法的语义。
每个这样的bean方法都会在生成的子类中被覆盖, 仅委托给实际的 bean 方法实现,如果 容器实际上请求构造一个新实例。
否则,对这样的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
}
}