Spring Framework 6正式發(fā)布,攜JDK 17&Jakarta EE開(kāi)啟新篇章
你好,我是YourBatman:一個(gè)俗人,貪財(cái)好色。
Title | Link |
所屬專欄 | |
源代碼 | |
程序員專用網(wǎng)盤(pán)公益上線啦,注冊(cè)送1G超小容量,幫你實(shí)踐做減法 | |
Java開(kāi)發(fā)軟件包(Mac) | https://wangpan.yourbatman.cn/s/rEH0 提取碼:javakit |
女?huà)z工程 | |
版本約定 | [Mac OS 13.0.1],[IDEA 2022.2.4] |
前言
在云原生發(fā)展勢(shì)頭下,Spring被冠以太重的標(biāo)簽,被新興框架Quarkus、Micronaut等嘲笑“廉頗老矣”??捎H是否可知,最初Spring就是以輕量級(jí)出圈(interface 21就是佐證),橫掃Java EE。
筆者在年初的文章早有“預(yù)告”,Spring團(tuán)隊(duì)2022年會(huì)有大動(dòng)作。從年初到年底,可謂千呼萬(wàn)喚始出來(lái):Sprng Framework 6終于GA(同時(shí)期的還有Spring Boot和Spring Cloud在前后腳都會(huì)發(fā)布RELEASE版本)。
Sprng Framework 5于2017年9月份發(fā)布,距今已有5年多了。作為Spring技術(shù)棧的底座:本次Spring Framework大版本號(hào)升級(jí)是阻斷式的,不向下兼容。
值得注意的是,本文并不嘗試解釋Spring Framework為何一躍將JDK的baseline從JDK 8提到JDK 17,以及廢棄javax啟用全新的jakarta命名空間,那是另一個(gè)系列的話題了。本文僅嘗試介紹新特性。
what’s new(新特性)
老規(guī)矩,將我們關(guān)心的功能爽一遍。
最低要求JDK 17
Spring Framework 6基于JDK 17構(gòu)建。換句話講,若想使用Spring Framework 6那么你的JDK環(huán)境最低要求JDK 17。市占率方面目前JDK 8其實(shí)已跌落至第二,曾經(jīng)的“你發(fā)任你發(fā),我用Java 8”終將成為歷史,這不Spring這次就來(lái)引領(lǐng)潮流。
問(wèn):同為L(zhǎng)TS版本的JDK,Spring團(tuán)隊(duì)為何沒(méi)選擇受眾更多的JDK 11而一躍選擇了更高版本的JDK 17呢?不怕栽跟頭嗎?
現(xiàn)在我創(chuàng)建一個(gè)Spring Framework 6的項(xiàng)目(基于maven構(gòu)建):
點(diǎn)確定后,加入依賴:
啟動(dòng)Spring容器的代碼:
成功運(yùn)行程序!
當(dāng)然若你不信邪,執(zhí)意用JDK 8運(yùn)行這段程序,那么你得到的將是這個(gè):
從Java EE邁向Jakarta EE
javax命名空間其實(shí)早已成為過(guò)去式,畢竟現(xiàn)在已快2023年了。這次Spring團(tuán)隊(duì)也是跟著JDK一起,順勢(shì)的完全摒棄掉了javax命名空間,擁抱Jakarta EE。
Jakarta EE估摸不少讀者可能沒(méi)聽(tīng)過(guò),沒(méi)關(guān)系!關(guān)于Java EE和Jakarta EE的“恩怨情仇(歷史淵源)”,感興趣的一定要看看筆者的這個(gè)系列:[YourBatman]-Java EE,給你說(shuō)得門(mén)清。
從Jakarta EE 9開(kāi)始,便使用了全新的jakarta.*命名空間。本次建議使用從Jakarta EE 10起步。對(duì)應(yīng)的技術(shù)主要有:
- Jakarta Servlet 6.0
- Jakarta Servlet JSP JSTL 3.0
- Jakarta Validation 3.0
- Jakarta WebSocket 2.1
- Jakarta Persistence 3.1
- Jakarta JMS 3.1
- Jakarta JSON 2.1
- Jakarta JSON Bind 3.0
- Jakarta Activation 2.1
- Jakarta Mail 2.1
- Jakarta Transaction 2.0
- Jakarta WS RS 3.1
- Jakarta XML SOAP 3.0
- Jakarta XML WS 4.0
另外,之前有些內(nèi)置進(jìn)JDK里面的Java EE注解,現(xiàn)在也換“包名”啦,如具有代表性的:JSR-330的@Inject、JSR 250的@PostConstruct、@Predestroy以及及其常用的@Resource注解。
LocalVariableTableParameterNameDiscoverer標(biāo)記為過(guò)時(shí)
LocalVariableTableParameterNameDiscoverer是ParameterNameDiscoverer的一個(gè)實(shí)現(xiàn)類,用于找出參數(shù)名。它是Spring的一個(gè)經(jīng)典實(shí)現(xiàn),早在Spring Framework 2.0就已出現(xiàn)。我們知道java代碼編譯后,默認(rèn)情況下參數(shù)名是不會(huì)保留的,而它利用了LocalVariableTable + ASM字節(jié)碼技術(shù)實(shí)現(xiàn)了參數(shù)名的查找。
直到Spring Framework 4.0(此版本開(kāi)始支持JDK 8),才出現(xiàn)了它的替代者:StandardReflectionParameterNameDiscoverer,基于JDK 8標(biāo)準(zhǔn)的參數(shù)化實(shí)現(xiàn)的。
JDK支持編譯時(shí)加上"-parameters參數(shù),便可保留方法參數(shù)的名字
一直以來(lái),Spring Framework為了考慮兼容性只能降低LocalVariableTableParameterNameDiscoverer的優(yōu)先級(jí)但并“不敢”打干掉它的注意。這次顯然不一樣勒,已經(jīng)標(biāo)記為過(guò)時(shí)了:
按照Spring OSS標(biāo)準(zhǔn),標(biāo)記為過(guò)時(shí)的類,在下個(gè)中型版本將會(huì)被移除。為此,Spring為了防止“亂用”,如若在運(yùn)行過(guò)程中發(fā)現(xiàn)你使用到了此類,會(huì)收到如下warn警告:
這是一個(gè)優(yōu)秀框架該有的樣子:完成了太多的非功能性需求,可謂想犯錯(cuò)都難。
ListenableFuture被標(biāo)記為過(guò)時(shí)
JDK最初有Futrue,而后Spring搞了一個(gè)增強(qiáng)版的ListenableFuture。直到Java 8的出現(xiàn):有了CompletableFuture再也不用使用ListenableFuture了。這不,這次順勢(shì)就把它拿下了。
除了ListenableFuture本身,與其相關(guān)的類都已被標(biāo)記為過(guò)時(shí),如:ListenableFutureCallback、SuccessCallback、FailureCallback等。
移除調(diào)CommonsMultipart等類
一直以來(lái)spring-web支持兩種上傳文件方式:
基于Apache Commons Fileuplod庫(kù)的CommonsMultipartResolver的解決方案
基于標(biāo)準(zhǔn)Servlet規(guī)范的StandardServletMultipartResolver解決方案
對(duì)應(yīng)的就是MultipartResolver接口的兩個(gè)實(shí)現(xiàn)類,如下圖所示(6之前的版本有兩個(gè)實(shí)現(xiàn)):
從本版本(Spring Framework 6)起,基于Apache Commons實(shí)現(xiàn)方案正式退出歷史舞臺(tái),相關(guān)類也已從源代碼里刪除。自此MultipartResolver有且僅有唯一實(shí)現(xiàn):
值得一提的是:起初Spring框架上傳文件推薦選擇的是基于Apache Commons庫(kù)的方案(也就是CommonsMultipartResolver),因?yàn)槟菚?huì)基于Servlet的方案性能有較大問(wèn)題;但隨著Servlet的更新(從Servlet 3.0開(kāi)始,javax.servlet.http.Part技術(shù)出現(xiàn)就不再有性能問(wèn)題了),問(wèn)題得到解決。
HttpMethod不再是枚舉,改為了類
HttpMethod是web開(kāi)發(fā)中比較常見(jiàn)的一個(gè)類,本次從enum -> class類型的變更絕大部分情況下都能兼容,只在某些特殊case下注意一下即可(比如不能再使用switch而需改為if else來(lái)做分支邏輯了)。
PS:HttpMethod改為類后重寫(xiě)了hashcode和equals方法,因此等值==比較也是不會(huì)有問(wèn)題的,請(qǐng)放心食用
Spring Framework 5.x版本:
Spring Framework 6版本:
RestTemplate最低要求HttpClient 5.x
RestTemplate是spring-web對(duì)http請(qǐng)求的抽象,它底層的實(shí)現(xiàn)技術(shù)可以是Apache HttpClient、OkHttp、JDK實(shí)現(xiàn)等等,具體采用什么技術(shù)是由ClientHttpRequestFactory的實(shí)現(xiàn)類決定的。
本次Spring Framework 6針對(duì)Apache的實(shí)現(xiàn),徹底摒棄Apache HttpClient 4.x,擁抱Apache HttpClient 5。
雖然底層實(shí)現(xiàn)有所變更,但若你代碼里是面向Spring的RestTemplate進(jìn)行編程的,那就可做到無(wú)感知。
僅標(biāo)注@RequestMapping注解不再被掃描為Controller了
喜大普奔!喜大普奔!喜大普奔!重說(shuō)三,懂的都懂。
在之前的Spring Framework版本中,spring-web會(huì)將標(biāo)注有@Controller注解或者標(biāo)注有@RequestMapping注解的掃描為一個(gè)控制器(controller):
這個(gè)動(dòng)作看似合理方便了使用,但這在Spring Cloud場(chǎng)景下非?!盁┤恕保篅FeignClient + API Jar包是現(xiàn)行微服務(wù)通信的典型使用方式。
在Spring Boot大一統(tǒng)的包掃描背景下,多數(shù)團(tuán)隊(duì)@EnableFeignClients也采用大一統(tǒng)的掃描策略,然而這就是“災(zāi)難”的開(kāi)始:非常容易得就將一個(gè)@FeignClient接口掃描為一個(gè)controller從而對(duì)外暴露了其所有接口,除了大大拖慢啟動(dòng)速度、造成URL沖突之外,進(jìn)而產(chǎn)生了重大安全隱患。
PS:雖然一般的公司在腳手架層面會(huì)默默的解決掉這個(gè)問(wèn)題,但據(jù)我了解絕大多數(shù)團(tuán)隊(duì)其實(shí)并未關(guān)注過(guò)此問(wèn)題,比如筆者寫(xiě)過(guò)的:
這下好了,Spring Framework 6幫我們解決了這個(gè)煩惱,這是它的判斷邏輯:控制器只認(rèn)@Controller注解了。
這讓我想起來(lái)有些同學(xué)使用@Bean去聲明一個(gè)控制器,現(xiàn)在是不行了(之前可以大概率是因?yàn)轭惿嫌蠤RequestMapping注解而誤打誤撞了),需要引起重視。
GenericApplicationContext支持AOT
支持AOT是Spring擁抱Native、擁抱云原生的基礎(chǔ),當(dāng)然這也是為何必須基于至少JDK 17構(gòu)建的原因之一。
對(duì)GraalVM native images提供一流的支持
GraalVM嘛,等下篇文章聊Spring Boot 3.0.0時(shí)再談。
PathMatchingResourcePatternResolver使用NIO和module方式掃描加速
Spring的scan一直是導(dǎo)致容器啟動(dòng)慢的重要愿意之一,甚至沒(méi)有之一。Spring Framework 6版本對(duì)此做了很大的優(yōu)化。
其實(shí),早在Spring Framework 5就采用了index方式進(jìn)行scan優(yōu)化,效果還是比較顯著的。但是此方式并不夠100%通用且使用起來(lái)不太方便,因此沒(méi)擊起什么浪花(默認(rèn)情況下并不會(huì)啟用)。這次不一樣了:將可選項(xiàng)變?yōu)榱吮剡x項(xiàng),更是唯一選項(xiàng)。
在此之前PathMatchingResourcePatternResolver只能通過(guò)掃xxx路徑下的所有文件(同步阻塞IO)來(lái)發(fā)現(xiàn)Bean。多module是JDK瘦身的一種方式,這次就利用多模塊 + GraalVM雙重優(yōu)勢(shì),來(lái)大大加快掃描的速度,核心代碼在這里:
強(qiáng)依賴micrometer的可觀測(cè)性
在Spring Framework 6的幾個(gè)(不是全部)子項(xiàng)目中使用micrometer進(jìn)行了直接的觀測(cè)性。比如:spring-web模塊現(xiàn)在就強(qiáng)依賴包io.micrometer:micrometer-observation來(lái)完成(編譯)工作:
micrometer之前只被用在Spring Boot中,現(xiàn)在Spring Framework部分子項(xiàng)目也接入了,這樣觀察將會(huì)更直接、更全面,這就是生態(tài)整合能力了吧。
總結(jié)
Spring Framework作為Java領(lǐng)域最為流行的框架(沒(méi)有之一),有非常龐大的用戶群體、項(xiàng)目歷史。這些歷史現(xiàn)在看來(lái)即是它的優(yōu)勢(shì),有時(shí)也會(huì)成為較重的包袱。
Spring團(tuán)隊(duì)自然能感知到“危機(jī)”,故有了Spring Native項(xiàng)目回應(yīng)“尚能飯否”。這次Spring Framework 6直接以JDK 17起底,并且對(duì)GraalVM native images提供一流支持,目的非常明確:(適當(dāng)?shù)模┧Φ舭?,證明我還行。
最后分享一句話:上山的人永遠(yuǎn)不要嘲笑下山的神。況且Spring依舊如日中天~