自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Spring Boot 2.6.0正式發(fā)布,循環(huán)引用終于被禁

開發(fā) 前端
北京時間2021年11月17日,Spring Boot 2.6.0正式發(fā)布?;貞浺幌律洗伟l(fā)版還是上次,相比于2.5.0版本的打醬油,本次的升級點更猛些。

[[440016]]

前言

北京時間2021-11-17,Spring Boot 2.6.0正式發(fā)布?;貞浺幌律洗伟l(fā)版還是上次,相比于2.5.0版本的打醬油,本次的升級點更猛些。

2.5.0版本的新特性在這里:【方向盤】Spring Boot 2.5.0正式發(fā)布,環(huán)境變量可指定前綴的功能很贊)

說明:Spring Boot 2.6.1隨后作為補丁版本立馬發(fā)布了,修復了若干問題。因此保持習慣,生產(chǎn)上請盡量保持最新的(小)版本

所屬專欄

  • 【方向盤】-Spring Boot新特性

相關(guān)下載

  • 【本專欄源代碼】:https://github.com/yourbatman/FXP-java-ee
  • 【技術(shù)專欄源代碼大本營】:https://github.com/yourbatman/tech-column-learning
  • 【女媧Knife-Initializr工程】訪問地址:http://152.136.106.14:8761
  • 【程序員專用網(wǎng)盤】公益上線啦,注冊送1G超小容量,幫你實踐做減法:https://wangpan.yourbatman.cn
  • 【Java開發(fā)軟件包(Mac)】:https://wangpan.yourbatman.cn/s/rEH0 提取碼:javakit

版本約定

Spring Boot 2.6.0

正文

關(guān)于版本號,從2.4.x 版本開始版本號不帶 .RELEASE 后綴了!通過表格描述下Spring Boot各個版本現(xiàn)在的更新、維護狀況:

Spring Boot每年會在5月份和11月份發(fā)布兩個中型版本(一般都會有部分不向下兼容的情況,升級需謹慎),每個中型版本提供1年的支持(免費),提供2年+的商業(yè)支持(付費)。按此節(jié)奏可知:Spring Boot 2.6.0發(fā)布也宣布著2.4.x版本停止(免費)支持,而2.7.0版本預(yù)計會在2022年的5月份和大家見面。

2.6版本主要新特性

禁止循環(huán)引用

Spring Boot終究忍不住,禁止(Bean的)循環(huán)引用了!!!

注意:只是Spring Boot默認禁止了,但Spring Framework默認還是允許的哦

對于有代碼潔癖的開發(fā)者來說,看到循環(huán)引用的代碼是“不舒服”的。在業(yè)務(wù)開發(fā)中,有一種聲音是:循環(huán)引用不可避免,但實際上應(yīng)該思考:若出現(xiàn)了循環(huán)引用,必定是結(jié)構(gòu)設(shè)計上不合理導致,有優(yōu)化空間!若你是個有追求的程序員,是可以很容易發(fā)現(xiàn)這種不合理的。

什么是循環(huán)引用?

如圖,循環(huán)引用一般指A引用B,B又引用了A。更極端一點的循環(huán)引用case可以是:A引用A,本文將以此為例進行代碼演示。

什么是循環(huán)依賴?它是循環(huán)引用的一種具象形式,如Spring Bean之間的循環(huán)依賴就屬于循環(huán)引用。大多數(shù)情況下,可認為循環(huán)依賴和循環(huán)引用語義上是相同的。

在Spring Boot場景下,準備Bean循環(huán)依賴的基礎(chǔ)代碼:

  1. /** 
  2.  * 在此處添加備注信息 
  3.  * 
  4.  * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a> 
  5.  * @site https://yourbatman.cn 
  6.  * @date 2021/12/11 20:43 
  7.  * @since 0.0.1 
  8.  */ 
  9. @Service 
  10. public class AService { 
  11.  
  12.     @Autowired 
  13.     private AService aService; 
  14.  
  15.     @PostConstruct 
  16.     private void init() { 
  17.         System.out.println("循環(huán)依賴:" + (this == aService)); 
  18.     } 
  19.  

2.6.0之前版本(以2.5.x為例)

  1. <parent> 
  2.     <groupId>org.springframework.boot</groupId> 
  3.     <artifactId>spring-boot-starter-parent</artifactId> 
  4.     <version>2.5.7</version> 
  5. </parent> 

啟動Spring Boot應(yīng)用,控制臺輸出:

結(jié)果:正常啟動。這便是我們口頭上常說的:Spring已經(jīng)解決了Bean的循環(huán)依賴問題

2.6.0及之后版本

  1. <parent> 
  2.     <groupId>org.springframework.boot</groupId> 
  3.     <artifactId>spring-boot-starter-parent</artifactId> 
  4.     <version>2.6.0</version> 
  5. </parent> 

啟動Spring Boot應(yīng)用,控制臺輸出:

結(jié)果:啟動失敗。這便是從Spring Boot 2.6.0版本起禁止了循環(huán)引用的結(jié)果

如何解決循環(huán)引用?

文上有說到,循環(huán)引用屬于不合理的設(shè)計,但并非不能正常工作。這就像每個程序員都吐槽過屎山代碼依舊能正常work同一個道理:它不好,但有意義。

既然“不合理”,那就有理由規(guī)避。針對循環(huán)引用的解決方案,總結(jié)一下主要有兩種:

確保循環(huán)引用不再存在:整改/優(yōu)化業(yè)務(wù)邏輯

允許循環(huán)引用:無需改代碼

方案一:確保循環(huán)引用不再存在

好,這很好!難,這很難!本方案是最好的,也是最難的,Spring團隊當然最喜歡你這么去做,做難事必有所得嘛!

從Spring Boot 2.6.0開始的這個默認行為(不允許循環(huán)引用)能感受到:循環(huán)引用的編碼方式是不被推薦的,是壞味道的代碼。為此,期望正在看本文的coder給自己立個flag哈:不再寫循環(huán)引用的代碼,盡量吧😄。

奈何,好的東西/方案實現(xiàn)起來一般都很難,循環(huán)引用亦是如此。在筆者認為難點主要在程序員本身,主要表現(xiàn)在這三點:

思考不足。提起需求就開工看起來效率很高,實則往往相反

眼光不遠。這是短期利益和長期收益的PK,短期利益更具誘惑性,然而長期收益才具備更高價值

追求不夠。明明知道這么做不太好,但就是這么做了??朔щy好比打怪升級,過關(guān)斬將方能提高自己的上限

從A點到B點,若距離只有10m,走路的方式是最快的;若有1km,自行車是最佳;若超過10km,就是小汽車;若超過1000km,當選火車/飛機!總而言之:能夠積累才叫多,不用重來才叫快!

方案二:允許循環(huán)引用

此方案更像是繞過問題而非解決問題本身!!!

它是一種妥協(xié)方案而非最佳實踐。在Spring Boot 2.6.0之前版本無需擔心此問題(默認允許循環(huán)引用),若你準備使用2.6.x但現(xiàn)實情況依舊必須允許循環(huán)引用那該怎么辦呢?

有哪些現(xiàn)實情況呢?諸如:老項目升級Spring Boot版本需要保持向下兼容性;公司coder的水平不一,強制高標準的要求將會嚴重影響到生產(chǎn)效率等等

為此,做法只有一個:禁用默認行為(允許循環(huán)引用)。具體做法也很簡單,其實在文上啟動失敗的報錯詳情里Spring Boot已非常貼心的告訴你了:

所以只需在配置文件application.properties里加上這個屬性:

  1. spring.main.allow-circular-references = true 

再次啟用Spring Boot 2.6.0版本的應(yīng)用:正常啟動。

除了加屬性這個方法之外,也可以通過啟動類API的方式來設(shè)置,能達到同樣效果:

  1. public static void main(String[] args) { 
  2.     new SpringApplicationBuilder(Application.class) 
  3.             .allowCircularReferences(true) // 允許循環(huán)引用 
  4.             .run(args); 

我們知道,允許循環(huán)引用與否其實是Spring Framework的能力,Spring Boot只是將其暴露為屬性參數(shù)方便開發(fā)者來控制而已。那么問題來了,如果是一個構(gòu)建在純Spring Framework上的應(yīng)用,如何禁止循環(huán)引用呢?你知道怎么做嗎?歡迎在留言區(qū)討論作答,或私聊我探討學習~

加餐:允許循環(huán)引用了但依舊報錯

也許你一直認為Spring已經(jīng)解決循環(huán)引用問題了,所以在使用過程中可以“毫無顧忌”。非也,某些“特殊”場景下可能依舊會碰壁,并且問題還很隱蔽不好定位,不信你看我層層遞進的給你描述這個場景:

說明:以下代碼在允許循環(huán)引用的Spring Boot場景下演示運行

基礎(chǔ)代碼:

本例使用@PostConstruct來模擬觸發(fā)方法調(diào)用,效果和Controller里調(diào)Service方法一樣哈

  1. @Service 
  2. public class AService { 
  3.  
  4.     @PostConstruct 
  5.     private void init() { 
  6.         String threadName = Thread.currentThread().getName(); 
  7.         System.out.printf("線程號為%s,開始調(diào)用業(yè)務(wù)fun方法\n", threadName); 
  8.         fun(); 
  9.  
  10.     } 
  11.  
  12.     public void fun() { 
  13.         String threadName = Thread.currentThread().getName(); 
  14.         System.out.printf("線程號為%s,開始處理業(yè)務(wù)\n", threadName); 
  15.     } 
  16.  

啟動應(yīng)用即觸發(fā)動作,控制臺輸出為:

  1. 線程名為main,開始調(diào)用業(yè)務(wù)fun方法 
  2. 線程名為main,fun方法開始處理業(yè)務(wù) 

完美!此時,你發(fā)現(xiàn)fun方法執(zhí)行時間太長,需要做異步化處理。你就立馬想到了使用Spring提供的@Async注解輕松搞定:

  1. @Async 
  2. public void fun() { 
  3.  ... 

再次運行,控制臺輸出:

  1. 線程名為main,開始調(diào)用業(yè)務(wù)fun方法 
  2. 線程名為main,fun方法開始處理業(yè)務(wù) 

what?木有生效呀!這時你靈機一動,原因是沒用開啟該模塊嘛。所以你迅速的使用@EnableAsync注解啟用Spring的異步模塊,滿懷期待的再次運行應(yīng)用,控制臺輸出:

  1. 線程名為main,開始調(diào)用業(yè)務(wù)fun方法 
  2. 線程名為main,fun方法開始處理業(yè)務(wù) 

what a ...?怎么還是不行。你撓了撓頭,想起來之前踩過的“事務(wù)不生效的坑”,場景和這類似,所以你模仿著采用了相同的方式來解決:自己注入自己(循環(huán)依賴)

  1. @Autowired 
  2. private AService aService; // 自己注入自己 
  3.  
  4. @PostConstruct 
  5. private void init() { 
  6.  ... 
  7.     aService.fun(); // 通過代理對象調(diào)用而非this調(diào)用 
  8.  

這次滿懷信心的再次運行,沒想到,啟動拋出BeanCurrentlyInCreationException異常

  1. org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'AService': Bean with name 'AService' has been injected into other beans [AService] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned offfor example. 
  2.  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:649) ~[spring-beans-5.3.13.jar:5.3.13] 
  3.  ... 

異常關(guān)鍵字:circular reference循環(huán)引用!!!不是說好了允許循環(huán)引用的嗎?怎么肥四?怎么破???

至此,筆者將此問題拋出,有興趣的同學可思考一下問題根因、解決方案哈。最終的效果應(yīng)該是不同線程異步執(zhí)行的:

  1. 線程名為main,開始調(diào)用業(yè)務(wù)fun方法 
  2. 線程名為task-1,fun方法開始處理業(yè)務(wù) 

Tips:筆者在之前的文章里對此問題有過非常非常詳細的敘述,感興趣的可自行向前翻哈!!!主動學習😄

更加靈活的自定義脫敏規(guī)則

對于/env和/configprops這兩個端點,常常會有敏感信息存在,比如:數(shù)據(jù)庫密碼等等。為了避免敏感信息外泄,一般做法是禁用這兩個端點,但粒度太粗,在很多時候是不合適的,因為這可能大大增加調(diào)試程序、定位問題的復雜程度,所以對該端點的某些信息脫敏不失為一個折中的好辦法。

Spring Boot使用Sanitizer(中文意思:消毒殺菌劑)來進行脫敏。比如屬性配置有如下配置:

  1. mysql.password = 123456 
  2. redis.pwd = 654321 

這時候訪問端點/actuator/env,得到的結(jié)果是這樣子的:

如圖所示,感覺有點厚此薄彼有木有???其實一切事出有因,EnvironmentEndpoint使用Sanitizer進行脫敏處理,而它自帶一些默認行為:

若不再這個范圍內(nèi)的key(比如上面的redis.pwd)也需要脫敏,很簡單,價格配置項即可:

  1. management.endpoint.env.additional-keys-to-sanitize = redis.pwd 
  2. #management.endpoint.env.additional-keys-to-sanitize = pwd # 脫敏范圍更大 

效果如下:

完美脫敏!!!這么做可以搞定絕大部分場景,但是某些特殊情況下,通過這種配置不是很好做,比如:同一個key,在不同的屬性源里表現(xiàn)不一樣。在application.properties里的話脫敏,而在application-dev.properties里不需要脫敏(開發(fā)環(huán)境嘛,明文裸奔更有助于調(diào)試程序)。

這個case若適用上面配置的方式不可處理,確切點說很不方便吧。Spring Boot意識到了這個“難點”,在2.6.0版本了新增了更靈活的自定義脫敏規(guī)則的能力,做法很簡單:自定義SanitizingFunction類型的Bean即可。

  1. // Since: 2.6.0 
  2. @FunctionalInterface 
  3. public interface SanitizingFunction { 
  4.  SanitizableData apply(SanitizableData data); 

比如關(guān)于Redis的配置項放redis.properties文件里,然后讀進來:

  1. @PropertySource("classpath:redis.properties"
  2. @Configuration(proxyBeanMethods = false
  3. public class AppConfiguration {} 
  4.  
  5. redis.properties文件內(nèi)容: 
  6. redis.pwd = 654321 

要求:redis.properties文件里面所有包含pwd的key的值都做脫敏處理,而其它屬性源不管。這時使用上面配置方式就無法實現(xiàn)了(或者說很難實現(xiàn)吧),Spring Boot 2.6.0新增的特性,API方式可以非常靈活方便的搞定:

  1. @Bean 
  2. public SanitizingFunction pwdSanitizingFunction() { 
  3.     return data -> { 
  4.         org.springframework.core.env.PropertySource<?> propertySource = data.getPropertySource(); 
  5.         String key = data.getKey(); 
  6.          
  7.         // 僅對redis.properties里面的某些key做脫敏 
  8.         if (propertySource.getName().contains("redis.properties")) { 
  9.             if (key.equals("redis.pwd")) { 
  10.                 return data.withValue(SANITIZED_VALUE); 
  11.             } 
  12.         } 
  13.         return data; 
  14.     }; 

再次請求/actuator/env端點,結(jié)果如下:

Spring MVC默認使用全新匹配策略

在Spring Framework 5之前,關(guān)于路徑匹配一直以來有且只有一種方式:基于Ant風格的url匹配,也就是熟悉的AntPathMatcher。在5.0版本之后引入了全新的路徑匹配器:PathPattern。

關(guān)于它倆都啥意思,怎么用,有什么區(qū)別,不是本文的重點。筆者前面文章有詳細介紹,建議閱讀哈。這里給個電梯直達:Spring5新寵:PathPattern,AntPathMatcher:那我走?

Spring Boot從2.0.0版本開始構(gòu)建在Spring Framework 5之上,但它直到2.6.0版本才徹底的將Spring MVC的默認匹配從AntPathMatcher切換為了PathPattern,這也是本次版本升級的一大特征之一。代碼上體現(xiàn)在這里:

  1. // 2.5.7 
  2. public static class Pathmatch { 
  3.  private MatchingStrategy matchingStrategy = MatchingStrategy.ANT_PATH_MATCHER; 
  4.  
  5. // 2.6.0 
  6. public static class Pathmatch { 
  7.  private MatchingStrategy matchingStrategy = MatchingStrategy.PATH_PATTERN_PARSER; 

若你需要回到Ant的匹配方式上(比如擔心兼容性),只需加上一行簡單配置就成:

  1. spring.mvc.pathmatch.matching-strategy = ant-path-matcher 

Redis自動開啟連接池

現(xiàn)在,只要classpath里存在commons-pool2這個jar,就會自動為Redis開啟連接池(包括Jedis和Lettuce哦)。

在2.6.0之前的版本,配置Redis時是否啟用連接池是由使用者顯示來決定的,現(xiàn)在自動了,說明Spring Boot是推薦使用Redis時用連接池的哦。

從源代碼的角度,區(qū)別主要在這(以現(xiàn)在更為常用的Lettuce為例):

LettuceConnectionConfiguration

下面代碼是2.6.0版本做的改動:

可以看到策略是有變化的:之前默認關(guān)閉連接池需要顯示開啟,2.6.0之后是默認開啟需要顯示關(guān)閉。

Spring Boot 2.4.x停止維護

按照Spring Boot現(xiàn)在版本規(guī)則:官方只免費維護當前主線版本和次版本,發(fā)布新版本后上上個版本自然就停止維護嘍,倒逼開發(fā)者保持升級,用新版本產(chǎn)品,享受技術(shù)紅利呀!

說明:這里指的停止維護是官方免費維護,不包含商業(yè)付費維護

依賴升級

這部分一般不用太關(guān)心,稍微留一下主要的組件版本即可。

  • Spring Data 2021.1
  • Spring Kafka 2.8
  • Apache Kafka 3.0(Spring果然站在最前沿呀)
  • Commons Pool 2.11
  • Elasticsearch 7.15
  • Hibernate 5.6
  • Mockito 4.0
  • ...

刪除和棄用

按照規(guī)約,在Spring Boot 2.4.0里被標注為棄用@Deprecated的類在此版本將會被刪除?;貞?.4.0版本棄用了哪些?

Spring Boot 2.4.0最大升級就是對ConfigFileApplicationListener的升級。

電梯直達:Spring Boot 2.4.0正式發(fā)布,全新的配置文件加載機制(不向下兼容)

那時壯志雄心計劃下下個版本(也就是2.6.0版本)就可以移除此類,但Spring團隊這次還是擔心步子邁得太大扯著dan,留下了它并改口將在3.0里移除掉。

棄用類:

  • JDBC的AbstractDataSourceInitializer體系,使用DataSourceScriptDatabaseInitializer體系替代
  • Hibernate的SpringPhysicalNamingStrategy,使用CamelCaseToUnderscoresNamingStrategy替代
  • 測試框架的AbstractApplicationContextRunner類的幾個方法被啟用,使用新的RunnerConfiguration類替代

官網(wǎng)新增SUPPORT標簽頁

由于Spring Boot的更新迭代速度非???,每個版本的發(fā)版時間、維護周期一直困擾著廣大開發(fā)者,為此隨著2.6.0版本的發(fā)布,官網(wǎng)上非常暖心的提供了一個SUPPORT標簽來展示各個版本的情況:

以及當天所處的一個狀態(tài):

地址:https://spring.io/projects/spring-boot#support

總結(jié)

Spring Boot 2.6.0的更新點還是比較多的,值得肯定,當然也值得升級。

Java領(lǐng)域的云原生時代,雖然受到了挑戰(zhàn),但毫無疑問在未來的5年甚至10年,Spring Boot依舊是標準的腳手架,是云原生應(yīng)用的基礎(chǔ)設(shè)施。它的能力能解放開發(fā)者的精力,時間用于業(yè)務(wù)設(shè)計、開發(fā)上。

最后,多分享一句。筆者從中覺得的每次版本升級符合Spring的決策哲學:先服從,再引領(lǐng)。畢竟對于龐大的Spring體系來說,每個重要決策都并非拍腦袋就可以,背后需要宏觀思想作為指導。

拿循環(huán)引用這個例子來講,Spring Framework最初默認允許循環(huán)依賴:設(shè)計上似乎留下了“不和諧”,但那會Spring初出茅廬,話語權(quán)不夠,所以擁抱大眾,活下來才是第一位。Spring技術(shù)棧發(fā)展到現(xiàn)在成為了實際的開發(fā)標準,在Java領(lǐng)域可謂已有絕對的話語權(quán),因此它開始引領(lǐng):默認不允許循環(huán)引用。

【編輯推薦】

 

責任編輯:姜華 來源: Java方向盤
相關(guān)推薦

2018-05-30 14:56:24

Spring輕量化Java 8

2018-08-13 16:15:41

2018-06-20 15:42:09

2022-11-26 00:00:03

Spring指南體系

2019-05-17 15:26:06

Spring BootSpring BootJava

2022-12-12 08:34:57

SpringJava

2015-07-30 22:57:02

華為公有云/云計算

2022-12-01 16:01:39

iOSiOS 16信號

2022-12-05 16:02:56

iOSiOS 16信號

2023-10-07 11:18:23

iOS 17蘋果

2023-11-08 14:08:41

iOS 17蘋果

2017-03-31 14:31:08

QQ瀏覽器修復功能特性

2011-12-26 09:06:16

Java

2012-08-31 13:49:32

2009-12-17 10:25:39

Spring 3.0

2009-05-04 17:47:13

LinuxMandrivaSpring

2024-12-03 10:46:48

Spring優(yōu)化開發(fā)

2011-12-14 09:14:46

JavaJ2EESpring

2012-03-09 09:47:28

Wine 1.4正式版發(fā)布

2021-03-31 06:05:08

微信朋友圈騰訊
點贊
收藏

51CTO技術(shù)棧公眾號