@Configuration屬性proxyBeanMethods詳解

@Configuration註釋中的proxyBeanMethods參數是springboot1.0,升級到springboot2.0之後新增的比較重要的內容,該參數是用來代理bean的。

理論
首先引出兩個概念:Full 全模式,Lite 輕量級模式

Full(proxyBeanMethods = true) :proxyBeanMethods參數設置爲true時即爲:Full 全模式。 該模式下注入容器中的同一個組件無論被取出多少次都是同一個bean實例,即單實例對象,在該模式下SpringBoot每次啓動都會判斷檢查容器中是否存在該組件
Lite(proxyBeanMethods = false) :proxyBeanMethods參數設置爲false時即爲:Lite 輕量級模式。該模式下注入容器中的同一個組件無論被取出多少次都是不同的bean實例,即多實例對象,在該模式下SpringBoot每次啓動會跳過檢查容器中是否存在該組件
什麼時候用Full全模式,什麼時候用Lite輕量級模式?
當在你的同一個Configuration配置類中,注入到容器中的bean實例之間有依賴關係時,建議使用Full全模式
當在你的同一個Configuration配置類中,注入到容器中的bean實例之間沒有依賴關係時,建議使用Lite輕量級模式,以提高springboot的啓動速度和性能

proxyBeanMethods 屬性默認值是 true, 也就是說該配置類會被代理(CGLIB),在同一個配置文件中調用其它被 @Bean 註解標註的方法獲取對象時會直接從 IOC 容器之中獲取;

看下源碼註解
/**
* Specify whether {@code @Bean} methods should get proxied in order to enforce
* bean lifecycle behavior, e.g. to return shared singleton bean instances even
* in case of direct {@code @Bean} method calls in user code. This feature
* requires method interception, implemented through a runtime-generated CGLIB
* subclass which comes with limitations such as the configuration class and
* its methods not being allowed to declare {@code final}.
*

The default is {@code true}, allowing for 'inter-bean references' via direct
* method calls within the configuration class as well as for external calls to
* this configuration's {@code @Bean} methods, e.g. from another configuration class.
* If this is not needed since each of this particular configuration's {@code @Bean}
* methods is self-contained and designed as a plain factory method for container use,
* switch this flag to {@code false} in order to avoid CGLIB subclass processing.
*

Turning off bean method interception effectively processes {@code @Bean}
* methods individually like when declared on non-{@code @Configuration} classes,
* a.k.a. "@Bean Lite Mode" (see {@link Bean @Bean's javadoc}). It is therefore
* behaviorally equivalent to removing the {@code @Configuration} stereotype.
* @since 5.2
*/
boolean proxyBeanMethods() default true;

註解的意思是 proxyBeanMethods 配置類是用來指定 @Bean 註解標註的方法是否使用代理,默認是 true 使用代理,直接從 IOC 容器之中取得對象;如果設置爲 false, 也就是不使用註解,每次調用 @Bean 標註的方法獲取到的對象和 IOC 容器中的都不一樣,是一個新的對象,所以我們可以將此屬性設置爲 false 來提高性能;

根據註釋 proxyBeanMethods 是爲了讓使用 @Bean 註解的方法被代理而實現 bean 的生命週期的行爲。

設置爲 true,那麼直接調用方法獲取 bean,不會創建新的 bean,而是會走 bean 的生命週期的行爲。
設置爲 false, 那麼直接調用方法獲取 bean,會創建新的 bean,且不會走 bean 的生命週期的行爲。
Configuration 源碼
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
boolean proxyBeanMethods() default true;

}

測試驗證代碼
測試代碼
public class AnnotationConfigApplicationContextTest {
@Test
public void refresh(){
AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
MyBean myBean=ctx.getBean(MyBean.class);
myBean.sayHello();
YourBean yourBean=ctx.getBean(YourBean.class);
yourBean.sayHello();
}
}

Configuration 代碼,設置爲 false
@Configuration(proxyBeanMethods = false)
public class AppConfig {
@Bean
public MyBean myBean(){
return new MyBean();
}
@Bean
public YourBean yourBean(){
return new YourBean(myBean());
}
}

Mybean 代碼
public class MyBean {
public MyBean(){
System.out.println("MyBean construct......");
}
@PostConstruct
public void init(){
System.out.println("MyBean PostConstruct ....");
}
public void sayHello(){
System.out.println("Hi MyBean ,hello world!");
}
}

YourBean 代碼
public class YourBean {
public MyBean myBean;

public YourBean(MyBean myBean){
System.out.println("YourBean construct...");
this.myBean=myBean;
}
@PostConstruct
public void init(){
System.out.println("YourBean PostConstruct...");
}
public void sayHello(){
System.out.println("Hi YourBean ,hello world!");
}
}

執行 refresh 測試測試代碼結果(proxyBeanMethods = false)
MyBean construct...... 打印了兩次,說明被 new 了兩次

10:04:56.066 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myBean'
MyBean construct......
MyBean PostConstruct ....
10:04:56.069 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'yourBean'
MyBean construct......
YourBean construct...
YourBean PostConstruct...
Hi MyBean ,hello world!
Hi YourBean ,hello world!

執行 refresh 測試測試代碼結果(proxyBeanMethods = true)
MyBean construct...... 只打印了一次,說明只被 new 了一次。

10:06:51.727 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myBean'
MyBean construct......
MyBean PostConstruct ....
10:06:51.741 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'yourBean'
YourBean construct...
YourBean PostConstruct...
Hi MyBean ,hello world!
Hi YourBean ,hello world!

轉:https://www.1024sou.com/article/561144.html

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