Spring配置類爲什麼要分Full和Lite模式

本文基於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模式。整理下來,大致有以下這些場景:

  1. 類上標註有@Component註解
  2. 類上標註有@ComponentScan註解
  3. 類上標註有@Import註解
  4. 類上標註有@ImportResource註解
  5. 若類上沒有任何註解,但類內存在@Bean方法
  6. 標註有@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增強過的類了。

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章