成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring Boot 2.6.0正式發布,循環引用終于被禁

開發 前端
北京時間2021年11月17日,Spring Boot 2.6.0正式發布。回憶一下上次發版還是上次,相比于2.5.0版本的打醬油,本次的升級點更猛些。

[[440016]]

前言

北京時間2021-11-17,Spring Boot 2.6.0正式發布。回憶一下上次發版還是上次,相比于2.5.0版本的打醬油,本次的升級點更猛些。

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

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

所屬專欄

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

相關下載

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

版本約定

Spring Boot 2.6.0

正文

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

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

2.6版本主要新特性

禁止循環引用

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

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

對于有代碼潔癖的開發者來說,看到循環引用的代碼是“不舒服”的。在業務開發中,有一種聲音是:循環引用不可避免,但實際上應該思考:若出現了循環引用,必定是結構設計上不合理導致,有優化空間!若你是個有追求的程序員,是可以很容易發現這種不合理的。

什么是循環引用?

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

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

在Spring Boot場景下,準備Bean循環依賴的基礎代碼:

  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("循環依賴:" + (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應用,控制臺輸出:

結果:正常啟動。這便是我們口頭上常說的:Spring已經解決了Bean的循環依賴問題

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應用,控制臺輸出:

結果:啟動失敗。這便是從Spring Boot 2.6.0版本起禁止了循環引用的結果

如何解決循環引用?

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

既然“不合理”,那就有理由規避。針對循環引用的解決方案,總結一下主要有兩種:

確保循環引用不再存在:整改/優化業務邏輯

允許循環引用:無需改代碼

方案一:確保循環引用不再存在

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

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

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

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

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

追求不夠。明明知道這么做不太好,但就是這么做了。克服困難好比打怪升級,過關斬將方能提高自己的上限

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

方案二:允許循環引用

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

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

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

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

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

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

再次啟用Spring Boot 2.6.0版本的應用:正常啟動。

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

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

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

加餐:允許循環引用了但依舊報錯

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

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

基礎代碼:

本例使用@PostConstruct來模擬觸發方法調用,效果和Controller里調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,開始調用業務fun方法\n", threadName); 
  8.         fun(); 
  9.  
  10.     } 
  11.  
  12.     public void fun() { 
  13.         String threadName = Thread.currentThread().getName(); 
  14.         System.out.printf("線程號為%s,開始處理業務\n", threadName); 
  15.     } 
  16.  

啟動應用即觸發動作,控制臺輸出為:

  1. 線程名為main,開始調用業務fun方法 
  2. 線程名為main,fun方法開始處理業務 

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

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

再次運行,控制臺輸出:

  1. 線程名為main,開始調用業務fun方法 
  2. 線程名為main,fun方法開始處理業務 

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

  1. 線程名為main,開始調用業務fun方法 
  2. 線程名為main,fun方法開始處理業務 

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

  1. @Autowired 
  2. private AService aService; // 自己注入自己 
  3.  
  4. @PostConstruct 
  5. private void init() { 
  6.  ... 
  7.     aService.fun(); // 通過代理對象調用而非this調用 
  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.  ... 

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

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

  1. 線程名為main,開始調用業務fun方法 
  2. 線程名為task-1,fun方法開始處理業務 

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

更加靈活的自定義脫敏規則

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

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

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

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

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

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

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

效果如下:

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

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

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

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

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

要求:redis.properties文件里面所有包含pwd的key的值都做脫敏處理,而其它屬性源不管。這時使用上面配置方式就無法實現了(或者說很難實現吧),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端點,結果如下:

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

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

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

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

  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自動開啟連接池

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

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

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

LettuceConnectionConfiguration

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

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

Spring Boot 2.4.x停止維護

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

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

依賴升級

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

  • 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
  • ...

刪除和棄用

按照規約,在Spring Boot 2.4.0里被標注為棄用@Deprecated的類在此版本將會被刪除。回憶2.4.0版本棄用了哪些?

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

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

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

棄用類:

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

官網新增SUPPORT標簽頁

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

以及當天所處的一個狀態:

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

總結

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

Java領域的云原生時代,雖然受到了挑戰,但毫無疑問在未來的5年甚至10年,Spring Boot依舊是標準的腳手架,是云原生應用的基礎設施。它的能力能解放開發者的精力,時間用于業務設計、開發上。

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

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

【編輯推薦】

 

責任編輯:姜華 來源: Java方向盤
相關推薦

2018-08-13 16:15:41

2018-05-30 14:56:24

Spring輕量化Java 8

2018-06-20 15:42:09

2022-11-26 00:00:03

Spring指南體系

2019-05-17 15:26:06

Spring BootSpring BootJava

2015-07-30 22:57:02

華為公有云/云計算

2022-12-05 16:02:56

iOSiOS 16信號

2023-10-07 11:18:23

iOS 17蘋果

2022-12-01 16:01:39

iOSiOS 16信號

2022-12-12 08:34:57

SpringJava

2023-11-08 14:08:41

iOS 17蘋果

2017-03-31 14:31:08

QQ瀏覽器修復功能特性

2012-08-31 13:49:32

2009-05-04 17:47:13

LinuxMandrivaSpring

2009-12-17 10:25:39

Spring 3.0

2011-12-26 09:06:16

Java

2024-12-03 10:46:48

Spring優化開發

2011-12-14 09:14:46

JavaJ2EESpring

2012-03-09 09:47:28

Wine 1.4正式版發布

2021-03-31 06:05:08

微信朋友圈騰訊
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久av网站| 中文字幕在线观看一区 | 国产一区二区影院 | 中文字幕一区二区三区精彩视频 | 久久成人一区 | 久久久久国产一区二区三区四区 | 综合网在线 | 在线观看视频91 | 中文字幕在线播放第一页 | 国产欧美日韩精品一区二区三区 | 国产成人小视频 | 日韩视频一区二区 | 中文字幕在线剧情 | 91视频在线观看 | 久久久久久国 | 日本精品视频在线 | 日日摸夜夜添夜夜添精品视频 | 国产成人综合一区二区三区 | 黄色在线免费看 | 尤物视频在线免费观看 | 久久性| 国产精品不卡一区 | 天天草狠狠干 | 精品香蕉一区二区三区 | 国产精品精品久久久 | 精品国产欧美 | 久久久精品高清 | 视频一区二区国产 | 国产亚洲精品久久久久久牛牛 | 九一在线观看 | 欧美国产精品一区二区三区 | 黄色一级免费 | 亚洲一区久久 | 国产一级电影在线观看 | 欧美日韩精品影院 | 国产在线观看不卡一区二区三区 | 日韩成人在线电影 | 人人干人人舔 | 精品中文字幕久久 | 色综合久久伊人 | 国产精品久久久久影院色老大 |