本文基於Spring 5.2.15-RELEASE
關於Spring配置類的Full模式和Lite模式,如果沒有仔細閱讀過源碼或者官方文檔的話,估計很多人都不知道這個概念。所以我們先來解釋下這兩個概念。
概念解釋
@Configuration
public class DataSourceConfig {
...
@Bean
public DataSource dataSource() {
...
return dataSource;
}
@Bean(name = "transactionManager")
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
...
}
DataSourceConfig就是一個在Spring中非常常見的配置類,這個配置類本身也會被註冊成Spring容器中的一個Bean。上面這種配置方式默認的就是Full模式。爲什麼默認是Full模式呢?其實祕密就藏在@Configuration
這個註解中。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
// 默認會通過Cglib對產生Bean的方法進行增強
boolean proxyBeanMethods() default true;
}
這個註解有一個屬性proxyBeanMethods
。這個屬性的值默認是true,會通過Cglib對這個配置類進行增強,增強後這個配置類就顯得比較“重”,因此叫Full模式。如果我們將這個屬性設置成false的話,這個配置類產生的Bean就是原始的對象,比較“輕量級”,叫Lite模式。因此,Full模式和Lite模式最本質的區別是:配置類本身的Bean對象會不會被Cglib增強。
這裏再強調一個概念:Full模式和Lite模式都是說DataSourceConfig這個配置類是Full模式或者Lite模式。
Lite模式
上面提到,將@Configuration的proxyBeanMethods屬性設置成false就Lite模式的配置類,其實還有很多其他的場景也屬於Lite模式。整理下來,大致有以下這些場景:
- 類上標註有
@Component
註解 - 類上標註有
@ComponentScan
註解 - 類上標註有
@Import
註解 - 類上標註有
@ImportResource
註解 - 若類上沒有任何註解,但類內存在@Bean方法
- 標註有
@Configuration(***proxyBeanMethods = false***)
自Spring5.2(對應Spring Boot 2.2.0)開始,內置的幾乎所有的
@Configuration
配置類都被修改爲了@Configuration(proxyBeanMethods = false)
,以此來降低啓動時間,爲Cloud Native繼續做準備。
優點:
- 運行時不再需要給對應類生成CGLIB子類,提高了運行性能,降低了啓動時間
- 可以把該配置類當作一個普通類使用嘍:也就是說@Bean方法 可以是private、可以是final
缺點:
- 不能聲明@Bean之間的依賴,也就是說不能通過方法調用來依賴其它Bean
@Configuration(proxyBeanMethods = false)
public class DataSourceConfig {
...
@Bean
public DataSource dataSource() {
...
return dataSource;
}
@Bean(name = "transactionManager")
public DataSourceTransactionManager transactionManager() {
// 此處的dataSource()調用就是一次普通的方法調用,不會引用Spring IOC容器中的單列Bean
return new DataSourceTransactionManager(dataSource());
}
...
}
這個問題可以這樣解決
@Configuration(proxyBeanMethods = false)
public class DataSourceConfig {
...
@Bean
public DataSource dataSource() {
...
return dataSource;
}
@Bean(name = "transactionManager")
// 通過方法參數引用Spring容易中的Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource;
}
...
}
Full模式
標註有@Configuration
或者@Configuration(***proxyBeanMethods = true***)
的類被稱爲Full模式的配置類。
優點:
- 可以支持通過常規Java調用相同類的@Bean方法而保證是容器內的Bean;
缺點:
- 運行時會給該類生成一個CGLIB子類放進容器,有一定的性能、時間開銷;
- 正因爲被代理了,所以@Bean方法 不可以是private、不可以是final。
簡單總結
Spring的配置類分成Full和Lite兩種模式。
在Lite模式下
- 配置類本身不會被CGLIB增強,放進IoC容器內的就是配置類本身;
- 對於內部類是沒有限制的:可以是Full模式或者Lite模式;
- 配置類內部不能通過方法調用來處理依賴,否則每次生成的都是一個新實例而並非IoC容器內的單例
- 配置類就是一普通類嘛,所以內部的@Bean方法可以使用
private/final
等進行修飾
在Full模式下
- 配置類會被CGLIB增強(生成代理對象),放進IoC容器內的是代理對象;
- 對於內部類是沒有限制:可以是Full模式或者Lite模式;
- 該模式下,配置類內部可以通過方法調用來處理依賴,並且能夠保證是同一個實例,都指向IoC內的那個單例;
- 該模式下,@Bean方法不能被
private/final
等進行修飾(因爲方法需要被重寫,所以不能私有和final。defualt/protected/public都可以哦)
從上面的介紹可以看出來,Lite模式很大程度上是爲了減少啓動開銷,提升程序的啓動速度。所以如果你對程序的啓動速度很敏感,就使用Lite模式,但是一定要記住此時的配置類已經不是經過Cglib增強過的類了。