阅读Bean官方文档的@Bean Methods in @Configuration Classes和@Bean Lite Mode小节,可了解spring对Bean内部级联的处理。
什么是内部级联?
参考以下代码,首先我们介绍两个Bean对象,SuperBean 、InnerBean。InnerBean只有一个成员变量number
,SuperBean内部持有InnerBean的引用:
public class InnerBean {
public int number;
public InnerBean(int number) {
this.number = number;
}
}
public class SuperBean {
public InnerBean innerBean;
public SuperBean(InnerBean innerBean) {
this.innerBean = innerBean;
}
}
然后我们定义一个@Configuration,代码如下。方法superBean()
在创建对象时,new SuperBean(innerBean())
直接调用了方法innerBean()
。innerBean()
创建对象时,会赋予参数10:
@Configuration // 测试@Configuration
public class InnerBeanReference {
public static int NUMBER = 10;
@Bean
public SuperBean superBean() {
return new SuperBean(innerBean());
}
@Bean
public InnerBean innerBean() {
return new InnerBean(NUMBER);
}
}
当像代码中使用了@Configuration注解时,spring会自动对Bean进行内部级联,什么意思呢?就是当你在别处依赖注入InnerBean
时,得到的是SuperBean
的内部对象。
为了更好说明,我们看以下代码。代码中,我们使用@Autowired注入了SuperBean和InnerBean:
@SpringBootApplication
public class Application implements CommandLineRunner{
@Autowired private SuperBean superBean;
@Autowired private InnerBean innerBean;
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
testSuperBeanWithAutowired();
}
public void testSuperBeanWithAutowired() {
superBean.innerBean.number = 12;
System.out.println(innerBean.number); // output 12.
}
}
以上代码执行后,testSuperBeanWithAutowired
被调用,并输出12. 可见,注入的innerBean
正是superBean
的内部对象。
Bean内部级联的触发条件
Bean内部级联只在@Configuration下能生效。如果是在@Component或甚至没有注解的情况下,spring不会进行Bean内部级联。
比如,将上面的类InnerBeanReference的注解@Configuration改为@Component后,其它代码不变,则最后会输出10。
原理
当注解了@Configuration时,为了实现Bean内部级联,spring会使用CGLIB进行动态代理。官方将这个情况称作inter-bean references
。
当注解为@Component或其它时,spring只会把Bean方法视为普通的工厂方法,不会使用CGLIB进行动态代理。官方将这个情况称作@Bean Lite Mode
。
总结
- @Configuration内,spring会自动处理Bean级联问题。
- @Component等其它注解内,spring只会把Bean方法当做普通工厂方法对待
网友评论