Spring?@Configuration?proxyBeanMethods=false問題
Spring @Configuration proxyBeanMethods=false
開門見山,本文沒有原理只有結(jié)論,要點(diǎn)如下:
1、proxyBeanMethods=true,F(xiàn)ull 全模式,如不指定則默認(rèn)為 true,@Bean 修飾的方法會被代理。
2、proxyBeanMethods=false,Lite 輕量級模式,@Bean 修飾的方法不會被代理。
3、仔細(xì)觀察 proxyBeanMethods
這個詞語,顧名思義,是代理方法的(僅指代被 @Bean 注解的方法哦),所以它的作用肯定是跟當(dāng)前這個 @Configuration 中的 Bean方法有關(guān)的。
4、在同一個 @Configuration 配置類中,值為 true 時,某方法直接調(diào)用其他的 Bean方法獲取 Bean(方法返回值是Bean對象)時,不會創(chuàng)建新的 Bean,而是會從 Spring 容器中直接提?。ㄈ绻萜髦袥]有則會同放入容器中)。
5、當(dāng)值為 false 時,與第4點(diǎn)區(qū)別的是 “像調(diào)用普通的Java方法一樣,每次都會完整的執(zhí)行方法,然后返回一個全新的對象”,因?yàn)?false 的意思就是不要代理我的方法(不代理就沒有前置邏輯就原汁原味方法調(diào)用唄)。
6、如果你的同一個 Configuration 配置類中的多個Bean方法之間沒有這樣互相調(diào)用的需求,那么建議使用 Lite輕量級模式(設(shè)置 proxyBeanMethods=false),以提高 SpringBoot 的啟動速度和性能。
如下代碼示例中
是否設(shè)置 proxyBeanMethods = false
決定了 同學(xué)你好...
被輸出一次還是兩次。
@Configuration(proxyBeanMethods = false) public class TestConfig { @Bean public Student getStudent() { System.out.println("同學(xué)你好..."); return new Student(); } @Bean public Teacher getTeacher() { System.out.println("getTeacher() 方法被執(zhí)行..."); return new Teacher(getStudent()); } }
實(shí)驗(yàn)驗(yàn)證@Configuration中proxyBeanMethods = true和proxyBeanMethods = false的區(qū)別
proxyBeanMethods 注釋說明
如果看完英文注釋完全明白什么意思,OK可以直接關(guān)閉該頁面了。
因?yàn)槲铱赐炅艘活^霧水,所以才有下面的實(shí)驗(yàn)。
其實(shí)注釋文檔寫得很明白,看完本文再看注釋就豁然開朗了。
測試完整代碼
package com.testProxyBeanMethods; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @SpringBootApplication public class TestApplication { public static void main(String[] args) throws Exception { ConfigurableApplicationContext ctx = SpringApplication.run(TestApplication.class, args); while (true) { ctx.getBean(HelloConfiguration.class).test(); Thread.sleep(1000L); } } } @Configuration(proxyBeanMethods = false) class HelloConfiguration { //spring 容器托管的bean @Bean("person") //Scope可以不用加,默認(rèn)就是單例 public Person person() { System.out.println("===:make person " + System.currentTimeMillis()); return new Person(); } /** * 測試直接調(diào)用person()方法 */ public void test() { Person p = person(); System.out.println("+++person hash code:" + System.identityHashCode(p)); System.out.println("+++person name:" + p.getName()); } } /** * 定義一個class */ class Person { private String name; private static int i = 0; public Person() { name = String.valueOf(++i); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
當(dāng) proxyBeanMethods = true , person() 調(diào)用后返回的是同一個對象
當(dāng) proxyBeanMethods = fase , person() 調(diào)用一次生成一個新對象
結(jié)果說明
1.proxyBeanMethods=true 時, Spring用cglib 對HelloConfiguration 所有有@Bean的方法進(jìn)行了增強(qiáng),就算你直接調(diào)用person()方法,因?yàn)閏glib生成的代理類不會直接執(zhí)行person()里面的new Person() ,他會檢查是否有單例,有直接返回。
2. proxyBeanMethods=false 時,沒有對person()方法增強(qiáng),那么調(diào)用person()方法,就相當(dāng)于調(diào)用了一個普通方法,每次調(diào)用都是直接執(zhí)行了new Person() , 獲取的person對象都是new出來的,這個對象與spring容器無關(guān)(沒有被spring容器托管), 因?yàn)锧Bean,所以spring容器里面還有一個托管的person
3. 當(dāng)我們自己寫框架或者工具的時候,如果某個對象在框架內(nèi)部可以不是單例的,那么可以proxyBeanMethods=false ,
用于優(yōu)化性能和減少不必要的代理開銷
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章

Maven構(gòu)建SpringBoot集成MyBatis過程

關(guān)于File與MultipartFile的用法概述

Java基礎(chǔ)之?dāng)?shù)組模擬循環(huán)隊(duì)列

Spring中的@ExceptionHandler異常攔截器

Java爬蟲實(shí)戰(zhàn)抓取一個網(wǎng)站上的全部鏈接

SpringBoot 下集成緩存工具類 CacheManager

Java8 Stream API 詳細(xì)使用方法與操作技巧指南