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