本文主要是聊一聊Spring 5.2引入的针对Configuration Class
的优化及目的。
github地址
前言
自从Spring 3.0 引入@Configuration
这个配置类注解, 那就意味着Spring的XML配置文件的方式已经过去了,迎来了一个注解(java class)的崭新时代。因此Spring后面版本大量使用Configuration Class
, 而我们的工作学习中只要涉及到了Spring,这个Configuration Class
的大量使用也是不可避免的,所有大家对这个也是非常常见的。看一下@Configuration
这个注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
//5.2引入的feature
boolean proxyBeanMethods() default true;
}
- Configuration也是使用了Comonent元注解(适用于ComponentScan机制)
- proxyBeanMethods 5.2引入的优化功能,默认为Configuraion Class生成代理类(兼容老版本), 推荐使用不走代理的Configuration Class(proxyBeanMethods = false)
Configuraion Class为什么要走代理?
来看看下面的一个使用案例
@Configuration
public class DemoConfiguration {
@Bean
public BeanA beanA() {
return new BeanA();
}
@Bean
public BeanB beanB() {
return new BeanB(beanA());
}
}
可以看到BeanB的初始化使用到了beanA, 这种情况是经常能遇到的。Spring为了支持这种bean方法的直接引用,因此在老版本中强制将Configuraiton Class进行代理这种bean methods(这里指的是beanA()方法),来由Spring框架自己来处理【直接从底层容器(BeanFactory)来查找对应Bean】。
如果不加这层代理?
造成的后果就是我想依赖的bean并不是由Spring容器(BeanFactory)来进行管理的(那查找,依赖注入,自动代理,Spring Bean生命周期管理使用等等Spring提供的功能都无法使用了),这种情况并不是我想要的。因此Spring才加了这层代理。
Configuration Class最佳使用方式(5.2以后)
可以将上面的使用方式改造一下
@Configuration(proxyBeanMethods = false)
public class DemoConfiguration {
@Bean
public BeanA beanA() {
return new BeanA();
}
@Bean
public BeanB beanB(BeanA beanA) {
return new BeanB(beanA);
}
}
官方推荐的方式就是以下两点:
- 去除Configuration Class自动代理 - proxyBeanMethods = false
- 需要bean引用的使用依赖注入的方式(DI)
去除没必要代理的好处
- 提高Spring容器的启动效率
- 减少字节码内存占用损耗(代理都会新生成一份字节码)
好了,简单地梳理完了来龙去脉和使用方式,下面也可以来看看Spring是如何实现Configuration Class
bean方法代理的,不感兴趣的就可以跳过了。
Configuration Class代理原理
我们都知道Spring对于这种类的代理都是采用的CGLIB
,对于Configuraion Class
的代理也不例外。
为了节省篇幅我们直接切到ConfigurationClassEnhancer
Configuration Class
的代理生成器。
入口:Configuration Class统一处理器ConfigurationClassPostProcessor
看下CGLIB Enchancer配置的核心代码: