Configuration
最近看源码时,经常看了下@Configuration(proxyBeanMethods = false)这样的配置,但从命名上看应该是与代理有关的,于是抽个时间了解了下
proxyBeanMethods
首先这个是@Configuration注解中的一个参数,我们都知道,@Configuration是Spring中的配置类,一般用来申明Bean,在默认情况下proxyBeanMethods为true
含义
从源码中可以看到对该参数的描述如下:
- 该属性的作用是指定标注了@Bean的方法在执行生命周期的时候是否应该被代理。比如在代码中直接调用@Bean标注的方法时要返回共享的单例Bean实例(关闭代理之后不会返回共享的Bean实例)。
- 该特性是通过运行时CGLIB子类 实现的方法拦截。该子类有一些限制,比如配置类和它的方法不允许声明为final类型。
- 默认为true,即允许 “inter-bean references” 通过配置类内部的直接方法调用,也可以通过外部调用该配置类的@Bean标注的方法。如果该配置类是一个特殊的配置类:每一个@Bean标注的方法 都是自包含的,并设计为供容器使用的普通工厂方法,可以设置该属性为false,以避免CGLIB子类处理。
- 关闭Bean方法拦截可以高效的单独处理@Bean方法,就像声明在一个non-@Configuration类上一样,@Bean Lite Mode。这种行为类似于删除@Configuration原型。
当直接在Configuration中直接通过方法,实现实例件的属性依赖时,IDEA会有这样一段提示:
示例
先通过下面的示例看下现象:
两个配置类,写法差不多,区别在与proxyBeanMethods的配置以及AnimalCage属性的注入方法。
先看下GenericConfiguration配置的情况:
再看下ProxyConfiguration配置的情况:
会得到这样的现象:
- proxyBeanMethods = true时,从Spring容器中取出的Configuration是一个Cglib代理配置,否则是一个原始类型配置
- proxyBeanMethods = true时,多次调用Bean方法,每次都是一个新对象,否则都是同一个对象
- 从Spring容器中取出Bean,不管多少次,都是同一个对象,也就是单例的
Lite Full Mode
看到上面的现象后,我们有必要了解下Spring配置中的Lite和Full两种模式
lite模式包含:
- 被@Component修饰的类
- 通过@ComponentScan扫描的类
- 通过@Import导入的配置类
- 通过@ImportResource导入的Spring配置文件
- 没有任何Spring相关注解,类里面有@Bean修饰的方法
- 被@Configuration修饰,但proxyBeanMethods = false
full模式包含:
- 被@Configuration修饰,且属性proxyBeanMethods = true(默认)
full模式使用特性:
- full模式下的配置类会被Cglib代理生成代理类取代原始类型保存到在容器中
- full模式下的@Bean方法不能是private和final,因为方法会被重写
- 单例scope下不同@Bean方法可以互相引用,实现单实例的语义
lite模式使用特性:
- lite模式下的配置类不生成代理,原始类型进入容器
- lite模式下的@Bean方法可以是private和final
- 单例scope下不同@Bean方法引用时无法做到单例,通过@Bean方法生成的对象都是新的实例
结束语
@Configuration(proxyBeanMethods = false)的配置其实是Lite模式,这种模式下,配置类不会生成代理类,速度会更快,但是要注意,在配置类中的@Bean方法,不能用来实现单例级别的依赖。