深入介紹Spring框架及故障排除
前言:
曾幾何時(shí),Spring框架提供了比J2EE更輕量級(jí)和更靈活的解決方案。即使在2013年左右,我也很高興詳細(xì)了解當(dāng)時(shí)的新款Spring 4。如今,7年后,當(dāng)我看到春天的時(shí)候,我感到一陣恐慌。注釋和@ComponentScan
已經(jīng)用更好的東西取代了XML,這需要一個(gè)可視化工具來理解您的系統(tǒng)。Spring變成了一頭不斷生長(和變化)的水螅。我接手并試圖理解他人編寫的Spring應(yīng)用程序,這讓我很痛苦。最后但并非最不重要的一點(diǎn)是,Clojure教會(huì)了我代碼可以/應(yīng)該是多么簡單。那么,我對(duì)Spring的主要問題是什么?
(為了明確起見,當(dāng)我說Spring時(shí),我指的主要是Spring控制反轉(zhuǎn)(IoC)及其依賴注入子集。)
Spring的缺點(diǎn)
不可理解性
系統(tǒng)構(gòu)成的黑箱:
注釋和組件掃描對(duì)于讓應(yīng)用程序快速啟動(dòng)和運(yùn)行來說非常棒。但當(dāng)您試圖理解所述應(yīng)用程序時(shí),它們是一場噩夢(mèng)。由于@Configurations
和@bean
來自您的代碼庫、公司庫中的任何地方,并且可能來自±100MB的Spring依賴項(xiàng)(真實(shí)情況),因此不可能清楚地了解應(yīng)用程序的結(jié)構(gòu)和配置。您基本上需要一次又一次地為Spring和所有庫進(jìn)行RTFM,以便記住可能需要的所有內(nèi)容,并通讀整個(gè)代碼庫。諸如IntelliJ SpringBeans視圖之類的工具可能會(huì)有所幫助(如果您能夠正常工作的話)。
在這里,我完全同意Python的禪宗“顯式優(yōu)于隱式”
在一個(gè)典型的Clojure項(xiàng)目中,我轉(zhuǎn)到核心/主名稱空間,其中主函數(shù)啟動(dòng)服務(wù)器并為其提供一個(gè)處理函數(shù),可能(手動(dòng))使用一些中間件包裝,可能在內(nèi)部使用庫進(jìn)行路由。我還可能閱讀配置并傳遞它。我可以輕松地單擊瀏覽代碼,并查看代碼中的具體部分以及它們是如何協(xié)同工作的。即使是在cljdoc這樣的大型系統(tǒng)中。org有一個(gè)主功能啟動(dòng)服務(wù)器(這里是Integrant),并為其提供配置和“系統(tǒng)定義”(類似于Springbean樹)。一切都是明確的和可導(dǎo)航的。
按注釋編程
能夠向方法和類添加元數(shù)據(jù)非常棒。我對(duì)@GetMapping(“/”)
之類的東西沒有任何反對(duì)意見。但它通常被用來繞過Java的限制,并通過諸如@Scheduled
和@Transactional
之類的注釋實(shí)現(xiàn)橫切關(guān)注點(diǎn)。我曾經(jīng)是AOP的堅(jiān)定支持者,由于語言的限制,AOP仍然是Java開發(fā)人員不可或缺的工具,但我也意識(shí)到它的成本不容忽視。問題是,您無法輕松看到它在做什么(因?yàn)樗裁炊紱]做,只是數(shù)據(jù))。為了給您一個(gè)透視圖,替換@Transactional Person findPersonInDb(String personId) {..}
在Clojure中,我只需要用一個(gè)自定義宏來包裝它,例如:
(defn find-person-in-db [person-id] (transactional ...))
實(shí)質(zhì)性的區(qū)別是,我可以控制單擊導(dǎo)航到宏,并查看它在做什么,因此所有行為都在那里,供我檢查和理解。祝你在Spring找到答案!
故障排除
Spring是讓很多事情快速起步的好時(shí)機(jī)——直到某些事情失敗或不按預(yù)期工作為止。Spring是一個(gè)松散耦合的意大利面大球,在我痛苦的經(jīng)歷中,解決它是非常困難的。有很多文檔,但我經(jīng)常找不到我需要的答案。也許官方文件太膚淺,有時(shí)依賴于大量已有的知識(shí)。搜索互聯(lián)網(wǎng)有時(shí)提供了一個(gè)解決方案,有時(shí)至少提供了有用的指針,有時(shí)提供了誤導(dǎo)性/舊信息,有時(shí)什么都沒有。在進(jìn)行故障排除時(shí),您需要艱難地通過這個(gè)龐大復(fù)雜的類,這些類以某種方式協(xié)同工作(或應(yīng)該協(xié)同工作),以(似乎)神秘的方式受到類路徑上的jar和@Configurations
的影響,并希望您能夠偶然發(fā)現(xiàn)問題的原因。
例如,我花了相當(dāng)長的時(shí)間來理解Spring MVC應(yīng)用程序中的錯(cuò)誤處理是如何工作的。我們有一個(gè)@ControllerAdvice(["myapp.endpoint.api"]) myapp.endpoint.api.advice.ErrorHandler調(diào)用的ErrorHandler
(如果您記得拋出正確的異常類型),@Component myapp.spring.ErrorPagesCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>將container.addErrorPages(new ErrorPage("/error"))錯(cuò)誤發(fā)送到org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController,然后它將神奇地呈現(xiàn)我們的錯(cuò)誤。類路徑上的html。我意識(shí)到我再也不明白(如果我真的明白的話)它到底是如何工作的了。但要以所需的方式顯示錯(cuò)誤,無疑是一場斗爭。
另一個(gè)難點(diǎn)是理解為什么Spring返回404而不是預(yù)期的文件。我對(duì)它的請(qǐng)求處理有很多來之不易的知識(shí),也許有一天會(huì)成為一篇博客文章。
了解@Scheduled jobs
實(shí)際上是如何調(diào)度的,并試圖找出為什么一個(gè)作業(yè)沒有按預(yù)期運(yùn)行,以及增加線程池大小以使其不再被較慢的作業(yè)停止的神奇調(diào)用是什么,這需要幾天的時(shí)間和多次失敗的嘗試,我甚至放棄了一次或兩次。搜索互聯(lián)網(wǎng)提供了一些幫助,但肯定遠(yuǎn)遠(yuǎn)不夠。這是我的一般經(jīng)驗(yàn),與Spring有關(guān)。
在Spring升級(jí)后搜索突然出現(xiàn)的ClassNotFound
運(yùn)行時(shí)錯(cuò)誤,試圖找出哪個(gè)Spring JAR有這個(gè)類,哪個(gè)版本是正確的,或者如何更改配置以停止需要更改…? 不,謝謝你。
為什么是Spring IoC?
這是一個(gè)由兩部分組成的問題:為什么是Spring IoC?為什么是Spring?
許多開發(fā)人員都知道,Spring是一個(gè)成熟且流行的解決方案。它還為幾乎所有問題提供了解決方案,這些解決方案通常能夠很好地協(xié)同工作。您也可以快速開始。另一方面,你可能會(huì)爭辯說,這是夸大其詞,有遺留問題,而且——通過嘗試為每個(gè)人做每件事——沒有做得完美,更小、專注的解決方案可能更好(盡管你需要整合它們)。
為什么選擇依賴注入和IoC?您可以從中找到許多原因:使用依賴注入和IoC容器的好處是什么?。
其中一些是:
- 簡化-您的類不需要知道如何創(chuàng)建它們的依賴項(xiàng)(以及它們需要什么)。您可以將實(shí)例化和連接類的問題分離出來。
- 靈活性—您現(xiàn)在可以提供不同的/修飾的實(shí)現(xiàn)。因此,在測試中,您可以提供模擬實(shí)現(xiàn),在大型復(fù)雜系統(tǒng)中,通過交換新的實(shí)現(xiàn)(這部分取決于對(duì)接口的編程),您可以使用疑難解答裝飾器包裝依賴項(xiàng),從而使其更容易逐步重構(gòu)。
- 生命周期控制
查看維基百科上列出的優(yōu)點(diǎn)和缺點(diǎn)。但它有明顯的好處,這并不意味著你應(yīng)該在任何地方、任何事情上都使用它。記住成本和劣勢,做出有根據(jù)的決策。
我們通常在Clojure-f.ex中使用依賴注入。接下來是數(shù)據(jù)庫訪問庫。jdbc要求您將目標(biāo)數(shù)據(jù)源傳遞給每個(gè)調(diào)用。(這使您可以自由地創(chuàng)建自己的包裝器來控制數(shù)據(jù)源并將其傳遞給庫(如果您愿意的話)在Cognitect AWS API中構(gòu)造AWS客戶端時(shí),可以讓它創(chuàng)建默認(rèn)的底層HTTP客戶端,也可以提供自己的客戶端,這樣就可以覆蓋默認(rèn)的依賴關(guān)系。我們甚至有一些人喜歡使用的依賴注入框架,如組件和上下文,而其他經(jīng)驗(yàn)豐富的開發(fā)人員則覺得它們不必要。
選擇
當(dāng)談到Spring生態(tài)系統(tǒng)作為一個(gè)整體時(shí),您應(yīng)該始終應(yīng)用Alex的合理庫原則:不要添加庫,直到?jīng)]有庫的痛苦如此之大,您無法忍受沒有它的生活(并且在適當(dāng)探索了其他選擇之后)。
當(dāng)您需要依賴注入時(shí),最好手動(dòng)組合系統(tǒng)。當(dāng)前的小型微服務(wù)時(shí)代與誕生Spring的巨型應(yīng)用時(shí)代截然不同。你可以自己做(為什么不??。┗蛘呤褂靡环N重量輕、重點(diǎn)突出的解決方案來解決更為手動(dòng)的問題,例如Feather。盡可能喜歡編程配置。Feather仍然是由CDI的@Provides
驅(qū)動(dòng)的注釋,但至少您在一個(gè)“module”類中聲明了這些注釋,您顯式地向Feather注冊(cè)了這些注釋,并顯式地向Feather請(qǐng)求所需的實(shí)例。在過去,我們使用Guice和手動(dòng)調(diào)用來綁定每個(gè)微服務(wù)的主類。對(duì)于我這個(gè)當(dāng)時(shí)經(jīng)驗(yàn)豐富的Spring用戶來說,這似乎很奇怪,也很錯(cuò)誤,但我開始理解并欣賞它。甚至還有用于Spring Boot的(實(shí)驗(yàn)性)編程配置DSL JaFu(Kotlin,KoFu也有一個(gè))。
據(jù)一些人說,Jakarta(Java EE的后代)是Spring生態(tài)系統(tǒng)的一個(gè)更干凈、更小、更好的替代品。您還可以針對(duì)特定需求搜索單個(gè)解決方案。
我從一位受人尊敬的同事那里聽到了Micronaut的好消息,它提供了低開銷的DI和AOP、REST客戶端/服務(wù)器、反應(yīng)式、斷路器等,但它仍然依賴(似乎)類路徑掃描進(jìn)行配置,因此保留了我在Spring中的主要問題。還有反應(yīng)型Helidon SE,它具有“透明的”的開發(fā)經(jīng)驗(yàn);純java應(yīng)用程序開發(fā),無注釋,無依賴注入”與這兩個(gè)領(lǐng)域相同的領(lǐng)域是Quarkus,但其IoC基于CDI,因此與Spring有相同的問題。Eclipse Vert.X 專注于反應(yīng)式、事件驅(qū)動(dòng)的應(yīng)用程序有所不同,但提供了類似的功能(HTTP客戶端/服務(wù)器、OpenAPI、GraphQL、DB訪問、配置、斷路器、安全性、度量),并具有編程配置;相反,它不提供依賴注入(但您可能不需要它(盡管總線本身也有問題))。
其他人在說什么
在為本文做研究時(shí),我發(fā)現(xiàn)了一些值得分享的經(jīng)驗(yàn)和觀點(diǎn)。
著名的挪威軟件架構(gòu)師Johannes Brodwall寫道(2013年,再次遙遙領(lǐng)先于我):
我發(fā)現(xiàn)DI容器給我的一些直覺讓我改進(jìn)了設(shè)計(jì),但同時(shí),我發(fā)現(xiàn)當(dāng)我移除容器時(shí),解決方案變小了(這很好?。子趯?dǎo)航和理解,更易于測試。我發(fā)現(xiàn)使用容器的成本非常高,這會(huì)導(dǎo)致復(fù)雜性和大小的增加,以及一致性的降低。
在這場Quora討論中,有很多好的建議:為什么大多數(shù)母語不是Java的程序員似乎對(duì)Spring框架持反對(duì)意見,他們對(duì)Spring框架的哲學(xué)有什么不喜歡的?
這方面的問題是:Spring有點(diǎn)破壞了我們從使用Java中獲得的簡單性好處。Spring謹(jǐn)慎地將復(fù)雜性引入到您的項(xiàng)目中,當(dāng)它工作時(shí),框架表面上很簡單,但老實(shí)說,有多少人可以解釋Spring中發(fā)生的事情?調(diào)試Spring錯(cuò)誤通??雌饋硐袷悄g(shù),需要90%的猜測和模式匹配。Spring通常可以在項(xiàng)目開始時(shí)為您節(jié)省數(shù)周的工作時(shí)間,您可能會(huì)覺得這些好處是免費(fèi)的,但事實(shí)并非如此。在某些方面,您可以將其與在項(xiàng)目中使用動(dòng)態(tài)編程語言的早期好處進(jìn)行類比。在項(xiàng)目的初始階段,它會(huì)大大加快您的速度,但復(fù)雜性和技術(shù)債務(wù)會(huì)在稍后的階段打擊您。
(當(dāng)然,他與動(dòng)態(tài)編程語言的比較與我和其他人使用Clojure的經(jīng)驗(yàn)相反。)
所以他們改成了基于注釋的配置,被迫學(xué)習(xí),但我還是不喜歡。它仍然不是真正的Java。許多事情都是靠魔法發(fā)生的——當(dāng)它們沒有發(fā)生時(shí),它們都以同樣的方式失敗,什么都沒有發(fā)生。因此,您編輯并重新編譯,同樣不會(huì)發(fā)生任何事情。無法判斷您是否注釋了錯(cuò)誤的內(nèi)容,或者您的注釋所說的內(nèi)容是否與您認(rèn)為的不同,或者您是否構(gòu)建了錯(cuò)誤的測試。
如果有像樣的文檔,我還沒有看到。我最近研究了RequestParam,它是Spring MVC中普遍存在的一部分,以了解其語義。該頁面實(shí)際上是無用的。Javadoc是API通信的主要方式;即使有更好的文檔存在,這個(gè)頁面也不會(huì)告訴我太多。
關(guān)于現(xiàn)代Java應(yīng)用程序:
Main方法有一行起始Spring和許多類,每個(gè)類有5個(gè)注釋。它們是如何被實(shí)例化的,以什么順序,如果出現(xiàn)問題,如何調(diào)試這個(gè)過程
下面是我最討厭Spring的幾件事:
它確實(shí)會(huì)減慢應(yīng)用程序的啟動(dòng)時(shí)間,在運(yùn)行應(yīng)用程序之前,你不會(huì)知道你的應(yīng)用程序是否正常工作——在大型商業(yè)環(huán)境中,這意味著最多需要一個(gè)小時(shí)的構(gòu)建和部署時(shí)間…然后會(huì)得到大量的stacktrace,其中一半與內(nèi)部spring類有關(guān),一旦您超越了簡單的單例布線場景,Spring就會(huì)變得非常丑陋、非常脆弱和不可預(yù)測,這有助于您起步,但您走得越遠(yuǎn),維護(hù)的噩夢(mèng)就越大。
結(jié)論
那么,Spring是邪惡的,應(yīng)該不惜任何代價(jià)避免嗎?不需要。它使人們能夠克服Java的局限性,并提供了許多庫來解決實(shí)際問題。但它也是巨大、復(fù)雜的,而且維護(hù)成本很高。對(duì)引入庫持懷疑態(tài)度,考慮多種解決方案,并為您的案例選擇最佳解決方案,而不僅僅是Spring解決方案。即使在使用DI和IoC(Spring或其他)時(shí),也要努力實(shí)現(xiàn)最大的透明度,并且更喜歡編程配置而不是類路徑掃描。如果其他一切都失敗了,請(qǐng)編寫良好的(java)文檔,以便您的繼任者能夠理解您的系統(tǒng)。
到此這篇關(guān)于深入介紹Spring框架及故障排除的文章就介紹到這了,更多相關(guān) Spring框架 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot+redis+阿里云短信實(shí)現(xiàn)手機(jī)號(hào)登錄功能
這篇文章主要介紹了springboot+redis+阿里云短信實(shí)現(xiàn)手機(jī)號(hào)登錄功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-01-01Springboot整合quartz產(chǎn)生錯(cuò)誤及解決方案
這篇文章主要介紹了Springboot整合quartz產(chǎn)生錯(cuò)誤及解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06Mybatis foreach用法解析--對(duì)于list和array
這篇文章主要介紹了Mybatis foreach用法解析--對(duì)于list和array,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03springboot返回圖片流的實(shí)現(xiàn)示例
本文主要介紹了springboot返回圖片流的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08Mybatis使用MySQL模糊查詢時(shí)輸入中文檢索不到結(jié)果怎么辦
這篇文章主要介紹了Mybatis使用MySQL模糊查詢時(shí)輸入中文檢索不到結(jié)果的解決辦法的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07