官术网_书友最值得收藏!

2.1 Spring Boot的前塵往事

要想掌握并靈活運用Spring Boot,首先需要了解Spring Framework。

2.1.1 Spring Framework

Spring Framework的發明與Java規范的變遷有著千絲萬縷的聯系,在Java規范的早期版本中,Sun公司針對不同的開發場景創建了不同的規范,以此幫助Java開發者更高效、更專注地開發業務邏輯,這些規范包括J2SE、J2ME及專門為企業級應用打造的J2EE,而EJB規范又是當時J2EE規范中最核心的部分。

EJB 1.0發布于1999年,它最初由IBM提出,之后由Sun公司(Java語言創建公司,現已由Oracle收購)將其吸收進Java官方體系,最后由JCP(Java Community Process,是一個開放的國際組織,主要由Java開發者及被授權者組成)正式將其規范化。由于當時Java在業界風頭正勁,各大公司都廣泛地使用EJB規范來進行應用開發,在這種環境下,EJB規范幾乎成了Java企業級應用開發的代名詞。

但是任何技術都不是完美的,EJB自身存在各種問題,要求革新EJB技術的呼聲一浪高過一浪,無論是當時的學術界還是企業界都沒有符合要求的技術出現。一位名為Rod Johnson的開發者,結合自己扎實的理論知識和豐富的實踐經驗寫出了對當時及后來的Java開發者影響深遠的兩本著作Expert One-on-One J2EE Design and DevelopmentJ2EE without EJB,他通過這兩本書闡述了一種與當時主流EJB截然不同的開發方式,這兩本書也可以視為Spring framework的起源。

從設計思想來看,Rod Johnson認為當時的EJB框架太過繁重,程序員需要花費大量的時間和精力來實現EJB規范所要求的各種類,并且還要管理他們的生命周期,這完全違背了EJB提出時的初衷——“讓大部分程序員把精力都用在業務功能本身上”。為了解決這種本末倒置的問題,Rod Johnson提出了輕量級框架的概念,并將這種思想完全貫徹于Spring Framework。這也是此框架被稱為Spring的原因:傳統的J2EE開發讓開發者走進了冬天(Winter),而春天(Spring)將會是一個全新的開始。

Spring公開可查的最初版本成型于Rod Johnson的Expert One-on-One J2EE Design and Development一書,其1.0版本于2004年正式開源(其開源許可證為Apache 2.0 license),正式開源版本的Spring Framework以其獨特的開發方式和全新的設計理念震撼了整個Java開發者生態圈,它的核心概念如下:

(1)IoC(Inversion of Control,控制反轉)和容器

理解IoC的概念對掌握Spring Framework而言是十分重要的,因為所有Spring對象的組裝都基于此。在IoC概念中,控制是指依賴者和被依賴者的關系控制。在傳統的Java應用開發中,如果A類依賴于B類,那么B類對象的生命周期都由A類對象控制,從而形成A類與B類的強耦合關系。然而,在面向對象的編程體系中,強耦合是應當極力避免的,如果可以將B對象生命周期的控制從A對象中剝離,那么強依賴關系也不再成立,整體系統也更加符合面向對象的設計原則。

IoC的核心思想是,被依賴者不再由依賴者直接創建,而是交由專門的組裝者來控制,在組裝者創建出被依賴的對象之后,將其注入依賴者。通過這樣的設計,可以達到松散耦合和接口與實現分離的目的。如果讀者熟悉經典的GoF設計模式,那么在傳統的實現中,這種需求都將通過工廠模式來實現。熟悉工廠模式對理解Spring Framework和閱讀其源代碼都有很好的幫助。因此,筆者建議大家在學習Spring Framework之前,花一點時間了解設計模式中的工廠模式。

從實現的角度來理解IoC,它與依賴注入(DI,Dependency Injection)密不可分。假設A類依賴于B類(B類并不是一個實現類,只是一個實現聲明的接口,真正的實現類并不會直接暴露給A類),而且實現類的生命周期也由容器(組裝者)控制,B類的實現對象將由容器注入A類對象。則根據面向對象的設計理論,此時的A類依賴于接口B,而非依賴于接口B的實現類,從而使A類獲得了不再依賴于實現細節的能力,實現了松耦合的設計目標,A類不再控制B類的生命周期,而且根據業務需求,還可以切換接口B的實現類,以此滿足不同功能。

Spring Framework的作用是將普通的Java類經過一系列配置,再利用IoC容器將不同對象組裝在一起,最終形成一個可以運行的系統,Spring容器的作用如圖2-1所示。

圖2-1 Spring容器的作用

(2)AOP(Aspect Oriented Programming,面向切面編程)框架

要深入理解AOP,需要先從面向對象編程談起。Java是典型的面向對象編程語言,面向對象強調的是繼承和封裝,也是現實世界在程序的投影。如果有些代碼邏輯需要在很多類(class)中反復出現而且又與主干業務邏輯并無強關聯(比如應用開發中常見的日志,事務控制和審計功能等),那么應該如何設計呢?例如一臺機器肯定不會有打印日志這樣的功能,但從應用開發的角度來審視系統,這些功能又是不可或缺的。在AOP出現之前,通常使用經典設計模式來解決這類問題,設計師可以采用代理(Proxy)模式,Java語言也提供了動態代理的實現,盡管這些技術可以解決一部分組件間的強依賴問題,但是解決方案卻不夠優雅靈活,而且有很強的局限性。比如,最初的原生Java只能代理接口(interface)而無法代理類(class)。了解了面向對象編程和原生Java的短板之后,作為全新的技術,AOP又提供了哪些新思路和新方法呢?在深入細節之前,我們需要先了解AOP的幾個關鍵點。

切面(Aspect)是一組模塊化的且可以被多個類(class)復用的邏輯,當目標對象(Target Object)的一段程序在某個執行點(Join-Point)的切入點(Pointcut)判定為真時,切面邏輯(Advice)會被觸發執行,并將Aspect和Target Object連接在一起,形成一個真正可執行的切面邏輯,這個過程被稱為織入(Weaving)。開發者可以通過AOP的方式將業務邏輯和非業務邏輯進行分離,使二者的代碼組織和職責都更集中、更清晰。

我們常用的Spring AOP和AspectJ技術都是AOP理論的一種實現,但是二者的實現目標卻是各不相同。Spring AOP只針對Spring Framework需要的AOP功能提供簡單有效的實現,而AspectJ是一個大而全的AOP Java實現。不過,Spring Framework也提供了對AspectJ的支持,因此在使用Spring時也可以同時使用AspectJ的功能。此外二者的織入(Weaving)技術也是完全不同的,AspectJ采用了編譯(compile)期織入和類裝載期(classload)織入,而Spring AOP的織入技術則根據運行期的不同狀態可以在Java的動態代理技術或CGLIB代理技術之間切換,其具體實現方式如圖2-2所示。

圖2-2 Spring AOP的實現方式

基于IoC(DI)和AOP兩大強力支柱,Spring Framework提供給Java開發者一種全新的(就當時而言)開發體驗。與當時的其他框架都不同,Spring Framework并不只是一種通用框架,更多時候Spring Framework在充當一種類似于膠水的角色,將不同的組件整合在一起最終形成完備的系統。所以,它不僅為開發者提供各種便利性,而且具備將Java生態中的主流開源框架(如Hibernate、iBatis等)和Java語言規范(如JDBC、JMX、JMS等)融合的能力。此外,Spring Framework提倡無侵入式編程,既可以讓開發者享受使用框架的好處,又省卻了與框架代碼過度耦合的煩惱。典型的Spring應用有兩部分組成:一部分是與系統功能強相關的業務邏輯,另一部分是與業務無關的框架代碼,但此類框架代碼大部分已經被Spring簡化,開發者只需利用IoC和AOP技術,通過簡單的配置(前期以XML為主,在JDK 1.5之后以注釋(Annotation)為主)將二者融合在一起形成功能完整的Java應用。Spring Framework的架構如圖2-3所示。

圖2-3 Spring Framework架構圖

Spring Framework的主要組件及其功能列舉如下:

(1)Core Container

? Core模塊主要提供了最基礎的IoC和DI功能。

? Bean模塊主要實現了BeanFactory,在Spring語境下所有的Java類都會被注冊為Spring容器里的一個Bean,各種Bean的生命周期也都由BeanFactory來控制。所有bean的實例的創建、依賴的識別和Auto-wire都是由Bean模塊實現的。

? Context模塊基于Core和Bean之上,任何對象在Spring容器內都是Spring Bean,而任意Spring Bean都是定義在context之內的,Context類似于調用Bean和被調用Bean之間的媒介層。

? 在Spring容器的Bean定義中可以采用各種表達式查詢和操作容器中的對象,這就是SpEL(Spring Expression Language)提供的主要功能。

(2)Data Access/Integration

? JDBC模塊主要功能是封裝和簡化了JDBC相關的操作,提供了類似template的設計模式的實現。

? ORM模塊為各種主流的ORM框架提供了集成方案。例如JPA、Hibernate、iBatis的集成等。

? OXM模塊提供了Object和XML之間的映射、轉化和數據訪問等功能,其主要實現了JAXB、Castor、XStream等的集成。

? JMS模塊主要提供了Java體系下主流消息中間件的集成,例如ActiveMQ和RabbitMQ的集成。

? 事務(transaction)模塊支持Spring容器內的聲明式事務管理和編程式事務管理,主要通過AOP方式使普通的Bean具備了事務能力。

(3)Web

? Web模塊提供了最基礎的HTTP規范的Spring封裝,例如上傳下載、通過Servlet Listner實現的Spring容器初始化和WebApplicationContext實例的初始化。

? Web-Servlet封裝了Java Servlet規范,同時提供了Spring MVC的實現,Web-Portlet和Servlet從底層來看都是對MVC的實現,二者最大的不同之處是額外提供了Portlet環境下的系統支持,Web-Struts的主要功能是提供了Spring和經典的MVC框架Struts的集成。

? 隨著業界發展和互聯網時代的來臨,Servlet逐漸淡出了大部分的業務開發,Spring MVC和Spring Boot等框架封裝了Servlet的底層實現細節,開發者只需要幾行代碼就可以實現一個簡單的RESTful風格的接口。相比早期的Servlet技術而言,Spring MVC和Spring Boot技術大幅提高了構建Web應用的開發效率。盡管如此,也不要忘記Spring MVC的底層實現依賴于Servlet規范,Spring隱藏了很多的實現細節,如果讀者希望更好地掌握Spring Web模塊,就需要對Servlet相關的規范和實現做一定的了解。

注意:圖2-3是Spring官方給出的架構圖,但其形成時期是Spring 3.*時代,故而此圖與最新的Spring Web有較大差異,例如新的Spring Web版本增添了Reactive、WebSocket等新特性。由于本書并非專注于Spring Web,所以不在此一一詳述,請讀者自行探索。

(4)其他

? Spring AOP提供AOP的支持。

? Aspects集成了AspectJ。

? Instrumentation模塊提供了類植入(Instrumentation)支持和類加載器的實現,可以應用在特定的應用服務器中。該spring-instrument-tomcat模塊包含了支持Tomcat的植入代理。

? test模塊支持使用JUnit或TestNG對Spring組件進行單元測試和集成測試。它提供了Spring ApplicationContexts的一致加載和上下文的緩存。它還提供可用于獨立測試代碼的模仿(mock)對象。

在Spring Framework問世之后,因其風格優雅、簡潔易用,以及對RESTful等功能的良好支持,迅速地成為Java開發的事實標準,而EJB卻被開發者遺忘了。各大Web容器廠商也在重新評估,在Web容器中是否還需要繼續支持EJB。總而言之,Spring讓廣大Java應用開發者從復雜的框架代碼中解脫出來,更加專注于應用的業務邏輯,這一點廣闊而深遠地影響了整個Java生態圈。

雖然Spring公司(由Rod Johnson創建最初名為Interface 21,后改名為SpringSource)經過一系列資本運作已于2009年被VMware收購,而Rod Johnson本人也于2012年正式離開了VMware,但是Rod Johnson對整個Java生態圈的卓越貢獻將被永遠銘記。

2.1.2 Spring Boot

Spring Framework在成為Java生態的“事實標準”之后,雖然很長時間內熱度不減,但是后來沒有再推出過任何激動人心的新功能,反而是開發者在處理日益增長的業務需求和管理Spring的配置、依賴和應用部署等方面不斷面臨新的挑戰。特別是RESTful、微服務等概念的流行,以及互聯網快速迭代的開發模式的興起,使開發者們愈發希望可以擁有更敏捷、更高效的開發框架,同時開發者對服務器(或容器)的要求也更加傾向于輕量級。

在這種需求的驅動之下,開發者Mike Youngstrom于2012年在Spring官方的GitHub上提出了一個ID為SPR-9888的需求,他的需求代表了當時Spring Framework使用者的心聲,他的需求如下:“如果開發者完全遵循Spring規范構建程序,則這樣的程序與原生的Servlet規范差別是非常大的,同時這也讓此類程序對Servlet容器的要求大大降低。因此,如果Spring Framework能夠提供一個無需直接與Servlet容器交互的框架,那么將會大大地簡化開發者的工作”。

在此需求被提交給Spring官方一年之后,Spring Framework的開發者Phil Webb于2013年8月在GitHub上,代表官方正式對該需求做出了回復“我們將會創建一個名為Spring Boot的新項目來解決這些問題”,同時還給出了一個介紹Spring Boot項目的博客,這是Spring Boot第一次出現在大眾視野中。

通過前面的簡短介紹,我們了解了Spring Boot的來歷,現在對我們來說,更加重要的任務是學習Spring Boot的工作原理和它解決問題的能力。

在探討更多細節之前,我們需要明確Spring Boot并非要取代Spring Framework,它與傳統的Spring Framework分別是事物的一體兩面。Spring Boot的真正目標是幫助開發者減少傳統Spring應用所需的配置文件和復雜的依賴關系,進而加快應用迭代的速度。

回顧第1章開發Spring應用的方法,開發者不僅要正確地引用Spring Framework的模塊及版本,還要集成第三方依賴的兼容性,否則會導致應用無法啟動,或者發生嚴重的生產事故。除了依賴問題,傳統Spring應用的另外一個煩惱是——大量煩瑣的配置文件,雖然從JDK 1.5之后注解(Annotation)式編程被廣泛采用,但是在實際項目中,沒有配置文件的Spring項目是非常罕見的。因而在Spring Framework發展了十年以后,框架本身的復雜度加上各種業務邏輯交雜在一起,開發者不得不花費大量精力和時間去管理這些配置文件,想要對應用進行一次版本升級更是難上加難,需要大量的回歸測試和兼容性測試。在這樣的情形下,如果開發團隊中程序員對Spring Framework的掌握程度參差不齊,那么維持一個簡潔優雅的項目會變得非常困難,并且對新手而言,Spring Framework的學習過程也是相當曲折的。

基于此,Spring Boot為了幫助開發者更加快速地開發各式應用,其設計思想是盡量使用最佳實踐和默認配置來自動化裝配Spring應用中的各類Bean,從而避免大量的重復性代碼和配置文件。更通俗地講,有很多業界專家知道如何能盡量發揮Spring Framework的優點,同時規避其短處,這些專家的經驗被稱為最佳實踐。對新手而言,能夠直接利用這些最佳實踐不僅可以避免犯下各種低級錯誤,還可以節省開發成本。

因此,Spring官方開發者直接將各種最佳實踐全部打包進Spring Boot,它以一種自動配置的形式注入應用中,并針對各種依賴的版本管理,設計了全新的Spring Boot Starter框架,各個廠商可以基于Spring Boot Starter規范開發自己的Starter組件,將新的功能模塊集成到Spring Boot。此外,Spring Boot還提供了內置的輕量級應用服務器,通過以上創新設計,基于Spring應用的絕大部分基礎問題都已經被Spring Boot解決了。

這些全新的特性,讓Spring Boot一經推出就立即風靡整個Spring生態圈,也讓沉寂許久的Spring開發生態再次喧囂起來。各種主流開源軟件也開始提供自己的Starter,方便開發者適配Spring Boot,更多架構師在設計系統之初就將Spring Boot作為首選,同時還開始將舊項目逐步遷移到Spring boot上。一時間,Spring又回到了舞臺的中央。

主站蜘蛛池模板: 彩票| 富裕县| 旬阳县| 肇东市| 西林县| 牙克石市| 贵港市| 博客| 章丘市| 四子王旗| 楚雄市| 高阳县| 广丰县| 界首市| 扶风县| 信阳市| 苗栗市| 松潘县| 南通市| 电白县| 泽库县| 旬邑县| 浏阳市| 增城市| 忻城县| 丰城市| 龙江县| 华池县| 宁强县| 安福县| 长子县| 房产| 二连浩特市| 定陶县| 绥中县| 长武县| 石城县| 巍山| 谢通门县| 久治县| 沁阳市|