Spring Boot 3.0.0正式發(fā)布,Banner不再支持圖片&增強可觀測性
前言
2014年發(fā)布Spring Boot 1.0; 2018年發(fā)布Spring Boot 2.0; 2022年發(fā)布Spring Boot 3.0; 這節(jié)奏,是要跟世界杯/奧運會的頻率杠上呀?
PS:本屆世界杯三顆巨星已走倆,期待Messy。
Spring Boot 3.0.0是是首個支持Spring Framework 6以及支持GraalVM的版本。官方對各個版本支持時間表:
正文
如果把2014年發(fā)布1.0版比作Spring團隊的再次創(chuàng)業(yè),發(fā)布后火爆程度可謂風靡全球。到2018年發(fā)布2.0版本,已經(jīng)完全沒有對手了。今年剛發(fā)布的3.0版本直接上Java 17以及Jakarta EE 9起步,可謂站穩(wěn)腳跟后的引領(lǐng)風騷。
what’s new(新特性)
老規(guī)矩,將我們關(guān)心的功能爽一遍。
最低版本要求
Spring Boot 3.0.0對外部依賴有最低版本要求:
- JDK 17
- Graal 22.3
- Native Build Tools Plugin 0.9.17
- Spring Framework 6
借助Micrometer大大提升可觀測性
據(jù)說,Spring Boot內(nèi)部有專門一個“團隊”來做應用的可觀性,本次的借助Micrometer的升級,使得可觀測這件事在Spring Framework 6和Spring Boot 3.0.0內(nèi)部都變得更加簡單、易用!通過可觀測性,能更好的了解系統(tǒng)內(nèi)部的運行狀態(tài),做到胸有成竹。
Micrometer 1.10中引入的新的Observation API,它使得一個API就能搞定:metrics、tracing、logging指標觀測,并且還能傳遞上下文、傳播元數(shù)據(jù)等等,對使用者非常友好。
這個API的設計是降低使用門檻,希望用戶使用單一API,就能從中獲取到多種信息:metrics、tracing、logging
筆者窺探了一下Spring Boot針對Micrometer源代碼級別的變化,覺得值得用專題來做較為完整的表述,結(jié)合自己的一些使用經(jīng)驗,盡量去說清楚在項目中如何使用它來方便的觀測你的Application。
Log4j2增強
一句話:配置性更靈活、和Spring環(huán)境整合得更好了。
PS:一般情況下使用默認的logback即可。倘若你不是典型的高并發(fā)場景,不建議折騰Log4j2。
spring-web URL的匹配規(guī)則有變化
聲明:這項特性更改和Spring Boot無關(guān),屬于Spring Framework 6的變更。
包含Spring MVC和WebFlux在內(nèi)的URL 尾部斜杠 匹配方式,本次有調(diào)整:可參見PathMatchConfigurer類。
為了下掉trailingSlashMatch這個屬性,從Spring Framework 6開始將默認值由之前的true改為了fasle。雖然僅僅只是改了一個默認值,但這個變動其實還蠻大的,影響到了URL的匹配。
譬如,@GetMapping("/api/demo")之前版本即可匹配/api/demo亦可匹配上/api/demo/,自Spring Boot 3.0.0(其實是Spring Framework 6)版本后就不行了,只能匹配上前者,后者404。Spring Framework目前將此屬性只標記為了@Deprecated(since = "6.0")過期,并未刪除。因此若你從老項目里升級過來,那么請務必做好兼容,方式有兩種:
- 局部式:將需要兼容的接口URL顯示的寫出多個,如:@GetMapping({"/api/demo", "/api/demo/"})。
- 全局式:若需要“兼容”的接口過多,又或者沒法逐一排查,那么可以使用下面這種全局兼容的方式:
刪除對spring.factories自動配置的支持
在Spring Boot 2.7版本,引入了全新的INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件作為自動配置的文件,但那會依舊保留著對spring.factories的支持。
到了Spring Boot 3.0.0版本,刪除掉了spring.factories作為自動配置文件的支持。這個差異在AutoConfigurationImportSelector文件里體現(xiàn)出來:
值得注意的是:只是刪除了spring.factories作為自動配置文件的支持,而不是不再支持這種SPI語法了。畢竟像什么EnvironmentPostProcessor、AutoConfigurationImportFilter、FailureAnalyzer等加載實現(xiàn)類的方式用spring.factories還是非常方便的。
Spring Boot此舉,筆者覺得目的就想將自動配置文件的配置,和其它SPI配置分離(順便做做簡化),僅此而已。
@ConstructingBinding不能再標注在類上
從源代碼的角度看,改注解已經(jīng)不能再被標注在類上了(編譯不通過):
至于Spring Boot為何這么做?下面繼續(xù)說完就懂了。
改進的@ConstructorBinding檢測能力
現(xiàn)在,當使用@ConfigurationProperties注解進行屬性綁定時,如果類只有1個構(gòu)造器,則可以省略注解@ConstructorBinding,不需要標注在構(gòu)造器上。
PS:如果您有多個構(gòu)造器,則仍然需要使用@ConstructorBinding來告訴 Spring Boot 使用哪一個。
這樣一句話描述體感還是不強,還是來個demo跑一跑。標注有@ConfigurationProperties注解的屬性類(一般有稱作屬性類,不叫配置類),如下:
注:如下例中,此時筆者并未在這個唯一構(gòu)造器里標注@ConstructorBinding注解。
配置文件里寫好屬性的k-v:
通過@ConfigurationPropertiesScan將@ConfigurationProperties屬性文件加載進容器:
文件結(jié)構(gòu)如下:
以上示例代碼,在Spring Boot 2.7.x里運行結(jié)果為:報錯
在Spring Boot 3.0.0版本運行結(jié)果為:正常
見識到了Spring Boot 3.0.0升級的威力。
令我,對于有多個構(gòu)造器的case,筆者這里就不試了,建議有興趣者自行動手跑跑Demo,加強理解比看文章100遍都強。
題外話:@ConfigurationProperties使用最佳實踐
先說一個數(shù)據(jù):據(jù)筆者所見所聞,至少**95%**程序員使用@ConfigurationProperties的姿勢是錯的,并且不知道怎么做才是對的。
關(guān)于這個話題,在筆者之前有篇文章之前花大篇幅聊過,這里可再簡單提一提,避免你在使用時候還出現(xiàn)些七七八八的問題。
比如上例中,如果我這么使用:如下截圖,如果筆者沒猜錯的話,這大概率是你的使用方式吧。
當然你可能不用構(gòu)造器而是用get/set方法去處理,問題或許不會暴露出來,但不影響你繼續(xù)往下看哈。
從IDEA飄紅提示來看,這種用法就不對嘛。再次運行容器:
在Spring Boot 2.7.x里運行結(jié)果為:報錯
在Spring Boot 3.0.0版本運行結(jié)果為:報錯
我在網(wǎng)上看到一篇寫Spring Boot 3.0.0新特性的文章說到:改進的@ConstructorBinding檢測能力這項新特性部分支持,不建議使用!嗨,這個誤導性就比較強了。
說白了不是Spring Boot 3.0.0部分支持,而是使用者對屬性類Bean的使用姿勢不對:這從Spring Boot 3.0.0的報錯提示能看出端倪,明顯比2.7.x版本的報錯指向性更好,明確告訴了你原因依舊修復方式。
值得一提的是,如果編碼時這么使用,連IntelliJ IDEA都不同意:非常明顯的指出了問題所在:
PS:想要獲取IDEA這樣溫暖的提示,需要升級到最新版2022.3版本哦。
在屬性類Bean上標注@Configuration注解(或者@Component及其所有派生注解),是大多數(shù)程序員的錯誤使用方式。因為這里其實犯了幾大錯誤:
- @ConfigurationProperties它并非一個Configuration配置類,因此不能直接走Spring Bean的初始化邏輯。
- @ConfigurationProperties類如果直接被實例化為Bean,將繞過了其特有的前置處理邏輯,造成邏輯缺失,也就會造成隱患bug。
- Spring Boot專門提供有@EnableConfigurationProperties和@ConfigurationPropertiesScan(since 2.2)注解來將@ConfigurationProperties類正確的放入容器內(nèi)。
倘若走捷徑只需程序Run起來即可,那么這種問題積累多了,必將反噬。
如何發(fā)現(xiàn)最佳實踐?對于Spring內(nèi)部的組件,參考Spring Boot內(nèi)置實現(xiàn)即可,它自己的東西自己的使用姿勢就是絕對的權(quán)威。當然本質(zhì)還是對實現(xiàn)原理的理解(但理解曲線比較長),有興趣的可以看筆者之前的文章哈。
Apache Kafka啟用異步確認配置項
在KafkaProperties.Listener屬性配置類里,新增了asyncAcks屬性:
注意:此屬性只在當KafkaProperties.Listener.ackMode = MANUAL/MANUAL_IMMEDIATE的時候才生效。
異步ack可對應Kafka中間件的同步(sync)、異步(async)、oneway三種發(fā)送方式理解。
@SpringBootTest支持“調(diào)用”main方法
我們的Spring Boot應用入口是main方法,而@SpringBootTest測試時它并沒有執(zhí)行我main方法,而是自己啟的容器。這對于有些在main方法還寫了些代碼邏輯(比如設置個系統(tǒng)屬性啥的)的時候就比較難受了。
這次在@SpringBootTest注解上新增了一個屬性:
它的含義為:
下面我們來體驗一把:在main函數(shù)上輸出一行日志
測試類:
運行測試類,日志為:
可以看到完完整整的執(zhí)行了main方法(啟動了應用),因此只要main方法能夠執(zhí)行到的代碼、掃到的配置、加載到的Bean,都會被放入到測試上下文里。
程序啟動期間,不再查找主機名
2.7.x版本:啟動日志包含主機名。
3.0.0版本:啟動日志不再包含主機名。
代碼差異體現(xiàn)在:
為何要干掉這段邏輯呢?看下這段代碼的實現(xiàn)就知道了,還是比較耗時的:
這段邏輯干掉后,Spring Boot應用的啟動速度應該會有比較明顯的提升,收獲比較大。
不再使用JDK的SecurityManager
Java 17中,SecurityManager遭到棄用。同理,最低要求Java 17的Spring Boot 3.0.0也無理由再使用它了。
以Spring Boot的TomcatEmbeddedWebappClassLoader類舉例:上下對比可看出區(qū)別。
Banner不再支持圖片
先看看代碼差異(上為2.7.x版本,下為3.0.0版本):可以看到,Spring Boot 3.0.0直接干掉了ImageBanner這個實現(xiàn)類。因此現(xiàn)在類路徑下的banner.gif、banner.jpg、banner.png等圖片文件都將被忽略,反饋歸真,只支持文本類Banner了!
PS:有興趣的同學可以看看ImageBanner的實現(xiàn),很高級且很復雜,當然也很耗時。看完就明白這個版本為啥要干掉它了~
JMX默認也只暴露Health端點了
從Spring Boot 2.7開始,web端點默認只暴露health,這次JMX也來跟著保持一致了。
如若需要顯示控制其它端點,你可通過management.endpoints.jmx.exposure.include和management.endpoints.jmx.exposure.exclude屬性來自定義控制。
Actuator內(nèi)置端點的返回JSON序列化統(tǒng)一使用ObjectMapper
在直線版本中,端點返回的序列化方式和MVC接口的并不一致,因此可能出現(xiàn)一些怪異現(xiàn)象。現(xiàn)在好了:所有端點的返回值序列化,統(tǒng)一使用ObjectMapper來完成。
這個標準是通過:統(tǒng)一實現(xiàn)OperationResponseBody接口實現(xiàn)的。
值得注意的事:若你有自定義的endpoint,那么也可通過實現(xiàn)OperationResponseBody接口,來保持和內(nèi)置端點序列化的一致性。
spring.data屬性前綴改變
由于spring.data這個前綴保留給了Spring Data項目,因此之前Spring Boot上的有些配置需要做修改。
- spring.data.cassandra.? -> spring.cassandra.
- 解釋:由于使用cassandra不需要引入spring data項目,因此它“不配”用spring.data前綴。
- spring.redis.? -> spring.data.redis.
- 解釋:由于使用redis會自動引入spring data項目依賴,因此需要統(tǒng)一到spring.data前綴
其它升級/改版
- @AutoConfigureMetrics -> @AutoConfigureObservability。
- @ConstructorBinding注解遷移到org.springframework.boot.context.properties.bind包了(之前版本在外層)。
- 從這點能看出框架對職責邊界的強要求,日常點滴才能確保長久的不腐化。
- DiskSpaceHealthIndicator詳情里增加path的顯示。
- jakarta.validation.Configuration?現(xiàn)在可借助ValidationConfigurationCustomizer定制化器進行定制了。
- YamlJsonParser?類被刪除。原因為:SnakeYAML的JSON解析與其它JSON庫的解析行為不一致,為了避免用錯而導致問題,干脆刪除掉。推薦使用JsonParser代替之。
新增管理的組件:
- EhCache 3
- RxJava 3
- 移除管理的組件:
- Apache ActiveMQ(可謂終于放棄了)
- Atomikos(分布式事務管理器,支持XA協(xié)議)
- EhCache 2(畢竟3.x已為主流)
- Hazelcast 3
- Apache Solr(因為它基于Jetty的客戶端Http2SolrClient與Jetty 11不兼容)
- RxJava 1.x和2.x
- ANTLR 2
Spring體系的其它依賴升級
基本上都是大版本號升級,畢竟命名空間從javax.* -> jakarta.*這一步影響還是蠻大的。
- Spring Data 2022.0
- Spring Kafka 3.0
- Spring REST Docs 3.0
- Spring Security 6.0
- Spring AMQP 3.0
- Spring Batch 5.0
- Spring GraphQL 1.1
- Spring HATEOAS 2.0
- Spring Integration 6.0
- Spring LDAP 3.0
- Spring Retry 2.0
- Spring Session 3.0
- Spring WS 4.0
Jakarta依賴升級
Spring Boot管理上的為基于Jakarta EE 10(基線是Jakarta EE 9)
- Jakarta Persistence 3.1
- Jakarta Servlet 6.0
- Jakarta Validation 3.0
- Jakarta WebSocket 2.1
- Jakarta Activation 2.1
- Jakarta JMS 3.1
- Jakarta JSON 2.1
- Jakarta JSON Bind 3.0
- Jakarta Mail 2.1
- Jakarta Servlet JSP JSTL 3.0
- Jakarta Transaction 2.0
- Jakarta WS RS 3.1
- Jakarta XML SOAP 3.0
- Jakarta XML WS 4.0
主要三方依賴升級
自從用上Spring Boot,程序員基本很少再需要關(guān)心三方依賴的版本號了,交給Spring Boot既省心又放心。
早期程序員,應該有使用過spirng-bom的,深有體會。原來,Spring早就在籌劃幫我們解決業(yè)務邏輯之外的痛點了。
- Tomcat 10
- Jetty 11
- Undertow 2.2.20.Final
- Elasticsearch Client 8.5
- Hibernate Validator 8.0(實現(xiàn)了Jakarta Validation 3.0)
- Jackson 2.14
- Micrometer 1.10
- SLF4J 2.0(org.slf4j:slf4j-api:2.0.0)
- OkHttp 4.10(com.squareup.okhttp3:okhttp:4.10, 使用了kotlin封裝)
- Netty 4.1.77.Final
- Couchbase Client 3.4
- Flyway 9
- Groovy 4.0
- Hibernate 6.1
- Jersey 3.1
- jOOQ 3.16
- Kotlin 1.7.20
- Liquibase 4.13
- Lettuce 6.2
- Log4j 2.18
- Logback 1.4
- Micrometer Tracing 1.0
- Neo4j Java Driver 5.2
- R2DBC 1.0
- Reactor 2022.0
- SnakeYAML 1.32
- Thymeleaf 3.1.0.M2
總結(jié)
Spring Boot已然成為Java開發(fā)的基石,本次大版本升級,并且還是明確的阻斷式的,因此可以看到大多建議都是清一色:正確的廢話,所以筆者也來幾句廢話建議:
- 生產(chǎn)環(huán)境非常確定的:不要用,不要用,不要用。至少等下一個中型版本出來后再考慮,也就是Spring Boot 3.1.x。
- 因為不少依賴組件升級還沒跟上(特別是國產(chǎn)的),比如典型的mybatis-plus、druid等。
- 配置有較大變動,隱藏的坑多。如springsecurity、spring-data等。
- Spring Cloud對應的版本(2022.0.0)還未Release。
- 個人自己:把玩,把玩,把玩。看10篇相關(guān)文章介紹,抵不上自己把玩一次!
技術(shù)向前的大船,浩浩蕩蕩不可逆。作為技術(shù)人,我們能做的是keep moving,不管是技術(shù)架構(gòu)師還是業(yè)務架構(gòu)師,還是開發(fā)工程師!