《Spring實戰》讀書筆記-第1章 Spring之旅

  • 2020 年 4 月 10 日
  • 筆記

《Spring實戰》是學習Spring框架的一本非常經典的書籍,之前閱讀了這本書,只是在書本上寫寫畫畫,最近整理了一下《Spring實戰》的讀書筆記,通過部落格的方式進行記錄分享。俗話說,好記性不如爛筆頭,把學習到的知識記錄下來,方便溫故知新,讓更多的讀者可以學習到有關Spring框架的知識。

序號

內容

鏈接地址

1

《Spring實戰》讀書筆記-第1章 Spring之旅

https://blog.csdn.net/ThinkWon/article/details/103097364

2

《Spring實戰》讀書筆記-第2章 裝配Bean

https://blog.csdn.net/ThinkWon/article/details/103527675

3

《Spring實戰》讀書筆記-第3章 高級裝配

https://blog.csdn.net/ThinkWon/article/details/103536621

4

《Spring實戰》讀書筆記-第4章 面向切面的Spring

https://blog.csdn.net/ThinkWon/article/details/103541166

5

《Spring實戰》讀書筆記-第5章 構建Spring Web應用程式

https://blog.csdn.net/ThinkWon/article/details/103550083

6

《Spring實戰》讀書筆記-第6章 渲染Web視圖

https://blog.csdn.net/ThinkWon/article/details/103559672

7

《Spring實戰》讀書筆記-第7章 Spring MVC的高級技術

https://blog.csdn.net/ThinkWon/article/details/103562467

文章目錄

  • 1.1 簡化Java開發
    • 1.1.1 激發POJO的潛能
    • 1.1.2 依賴注入
    • 1.1.3 應用切面
    • 1.1.4 使用模板消除樣板式程式碼
  • 1.2 容納你的Bean
    • 1.2.1 使用應用上下文
    • 1.2.2 bean的生命周期
  • 1.3 俯瞰Spring風景線
    • 1.3.1 Spring模組
    • 1.3.2 Spring Portfolio
  • 1.4 Spring的新功能
    • 1.4.1 Spring 3.1新特性
    • 1.4.2 Spring 3.2新特性
    • 1.4.3 Spring 4.0新特性
    • 1.4.4 Spring 5.0新特性
  • 1.5 小結

本章內容:

  • Spring的bean容器
  • 介紹Spring的核心模組
  • 更為強大的Spring生態系統
  • Spring的新功能

1.1 簡化Java開發

Spring是一個開源框架,最早由Rod Johnson創建,並在《Expert Oneon-One:J2EE Design and Development》這本著作中進行了介紹。

縱覽全書,讀者會發現Spring可以做非常多的事情。但歸根結底,支撐Spring的僅僅是少許的基本理念,所有的理念都可以追溯到Spring最根本的使命上:解決企業級應用開發的複雜性,即簡化Java開發

Spring是如何簡化Java開發的?為了降低Java開發的複雜性,Spring採取了以下4種關鍵策略

  • 基於POJO的輕量級和最小侵入性編程;
  • 通過依賴注入和面向介面實現松耦合;
  • 基於切面和慣例進行聲明式編程;
  • 通過切面和模板減少樣板式程式碼。

幾乎Spring所做的任何事情都可以追溯到上述的一條或多條策略。在本章的其他部分,我將通過具體的案例進一步闡述這些理念,以此來證明Spring是如何完美兌現它的承諾的,也就是簡化Java開發。讓我們先從基於POJO的最小侵入性編程開始。

1.1.1 激發POJO的潛能

如果你從事Java編程有一段時間了,那麼你或許會發現(可能你也實際使用過)很多框架通過強迫應用繼承它們的類或實現它們的介面從而導致應用與框架綁死。一個典型的例子是EJB 2時代的無狀態會話bean。早期的EJB是一個很容易想到的例子,不過這種侵入式的編程方式在早期版本的Struts、WebWork、Tapestry以及無數其他的Java規範和框架中都能看到。

Spring竭力避免因自身的API而弄亂你的應用程式碼。Spring不會強迫你實現Spring規範的介面或繼承Spring規範的類,相反,在基於Spring構建的應用中,它的類通常沒有任何痕迹表明你使用了Spring。最壞的場景是,一個類或許會使用Spring註解,但它依舊是POJO。

Spring的非侵入編程模型意味著這個類在Spring應用和非Spring應用中都可以發揮同樣的作用。

1.1.2 依賴注入

控制反轉和依賴注入的關係和詳解可以查看這篇文章

Spring可以做很多事情,它為企業級開發提供給了豐富的功能,但是這些功能的底層都依賴於它的兩個核心特性,也就是依賴注入(dependency injection,DI)和面向切面編程(aspect-oriented programming,AOP)

依賴注入這個詞讓人望而生畏,現在已經演變成一項複雜的編程技巧或設計模式理念。但事實證明,依賴注入並不像它聽上去那麼複雜。在項目中應用DI,你會發現你的程式碼會變得異常簡單並且更容易理解和測試。

DI功能是如何實現的

任何一個有實際意義的應用(肯定比Hello World示例更複雜)都會由兩個或者更多的類組成,這些類相互之間進行協作來完成特定的業務邏輯。按照傳統的做法,每個對象負責管理與自己相互協作的對象(即它所依賴的對象)的引用,這將會導致高度耦合和難以測試的程式碼。

耦合具有兩面性(two-headed beast)。一方面,緊密耦合的程式碼難以測試、難以復用、難以理解,並且典型地表現出「打地鼠」式的bug特性(修復一個bug,將會出現一個或者更多新的bug)。另一方面,一定程度的耦合又是必須的——完全沒有耦合的程式碼什麼也做不了。為了完成有實際意義的功能,不同的類必須以適當的方式進行交互。總而言之,耦合是必須的,但應當被小心謹慎地管理。

通過DI,對象的依賴關係將由系統中負責協調各對象的第三方組件在創建對象的時候進行設定。對象無需自行創建或管理它們的依賴關係,如圖1.1所示,依賴關係將被自動注入到需要它們的對象當中去。

依賴注入會將所依賴的關係自動交給目標對象,而不是讓對象自己去獲取依賴。

創建應用組件之間協作的行為通常稱為裝配(wiring)。Spring有多種裝配bean的方式,採用XML是很常見的一種裝配方式。如果XML配置不符合你的喜好的話,Spring還支援使用Java來描述配置。

觀察它如何工作

Spring通過應用上下文(Application Context)裝載bean的定義並把它們組裝起來。Spring應用上下文全權負責對象的創建和組裝。Spring自帶了多種應用上下文的實現,它們之間主要的區別僅僅在於如何載入配置。

1.1.3 應用切面

DI能夠讓相互協作的軟體組件保持鬆散耦合,而面向切面編程(aspect-oriented programming,AOP)允許你把遍布應用各處的功能分離出來形成可重用的組件

面向切面編程往往被定義為促使軟體系統實現關注點的分離一項技術。系統由許多不同的組件組成,每一個組件各負責一塊特定功能。除了實現自身核心的功能之外,這些組件還經常承擔著額外的職責。諸如日誌、事務管理和安全這樣的系統服務經常融入到自身具有核心業務邏輯的組件中去,這些系統服務通常被稱為橫切關注點,因為它們會跨越系統的多個組件。

如果將這些關注點分散到多個組件中去,你的程式碼將會帶來雙重的複雜性。

  • 實現系統關注點功能的程式碼將會重複出現在多個組件中。這意味著如果你要改變這些關注點的邏輯,必須修改各個模組中的相關實現。即使你把這些關注點抽象為一個獨立的模組,其他模組只是調用它的方法,但方法的調用還是會重複出現在各個模組中。
  • 組件會因為那些與自身核心業務無關的程式碼而變得混亂。一個向地址簿增加地址條目的方法應該只關注如何添加地址,而不應該關注它是不是安全的或者是否需要支援事務。

圖1.2展示了這種複雜性。左邊的業務對象與系統級服務結合得過於緊密。每個對象不但要知道它需要記日誌、進行安全控制和參與事務,還要親自執行這些服務。

在整個系統內,關注點(例如日誌和安全)的調用經常散布到各個模組中,而這些關注點並不是模組的核心業務。

AOP能夠使這些服務模組化,並以聲明的方式將它們應用到它們需要影響的組件中去。所造成的結果就是這些組件會具有更高的內聚性並且會更加關注自身的業務,完全不需要了解涉及系統服務所帶來複雜性。總之,AOP能夠確保POJO的簡單性

如圖1.3所示,我們可以把切面想像為覆蓋在很多組件之上的一個外殼。應用是由那些實現各自業務功能的模組組成的。藉助AOP,可以使用各種功能層去包裹核心業務層。這些層以聲明的方式靈活地應用到系統中,你的核心應用甚至根本不知道它們的存在。這是一個非常強大的理念,可以將安全、事務和日誌關注點與核心業務邏輯相分

1.1.4 使用模板消除樣板式程式碼

你是否寫過這樣的程式碼,當編寫的時候總會感覺以前曾經這麼寫過?我的朋友,這不是似曾相識。這是樣板式的程式碼(boilerplate code)。通常為了實現通用的和簡單的任務,你不得不一遍遍地重複編寫這樣的程式碼。

遺憾的是,它們中的很多是因為使用Java API而導致的樣板式程式碼。樣板式程式碼的一個常見範例是使用JDBC訪問資料庫查詢數據。

Spring旨在通過模板封裝來消除樣板式程式碼。

1.2 容納你的Bean

在基於Spring的應用中,你的應用對象生存於Spring容器(container)中。Spring容器負責創建對象,裝配它們,配置它們並管理它們的整個生命周期,從生存到死亡(在這裡,可能就是new到finalize())。

容器是Spring框架的核心。Spring容器使用DI管理構成應用的組件,它會創建相互協作的組件之間的關聯。毫無疑問,這些對象更簡單幹凈,更易於理解,更易於重用並且更易於進行單元測試

Spring容器並不是只有一個。Spring自帶了多個容器實現,可以歸為兩種不同的類型。bean工廠(由org.springframework. beans.factory.eanFactory介面定義)是最簡單的容器,提供基本的DI支援。應用上下文 (由org.springframework.context.ApplicationContext介面定義)基於BeanFactory構建,並提供應用框架級別的服務,例如從屬性文件解析文本資訊以及發布應用事件給感興趣的事件監聽者。

雖然我們可以在bean工廠和應用上下文之間任選一種,但bean工廠對大多數應用來說往往太低級了,因此,應用上下文要比bean工廠更受歡迎。我們會把精力集中在應用上下文的使用上,不再浪費時間討論bean工廠。

1.2.1 使用應用上下文

Spring自帶了多種類型的應用上下文。下面羅列的幾個是你最有可能遇到的。

  • AnnotationConfigApplicationContext:從一個或多個基於Java的配置類中載入Spring應用上下文。
  • AnnotationConfigWebApplicationContext:從一個或多個基於Java的配置類中載入Spring Web應用上下文。
  • ClassPathXmlApplicationContext:從類路徑下的一個或多個XML配置文件中載入上下文定義,把應用上下文的定義文件作為類資源。
  • FileSystemXmlapplicationcontext:從文件系統下的一個或多個XML配置文件中載入上下文定義。
  • XmlWebApplicationContext:從Web應用下的一個或多個XML配置文件中載入上下文定義。

1.2.2 bean的生命周期

可以參考Spring容器中bean的生命周期

在傳統的Java應用中,bean的生命周期很簡單。使用Java關鍵字new進行bean實例化,然後該bean就可以使用了。一旦該bean不再被使用,則由Java自動進行垃圾回收。相比之下,Spring容器中的bean的生命周期就顯得相對複雜多了。正確理解Spring bean的生命周期非常重要,因為你或許要利用Spring提供的擴展點來自定義bean的創建過程。下圖展示了bean裝載到Spring應用上下文中的一個典型的生命周期過程。

bean在Spring容器中從創建到銷毀經歷了若干階段,每一階段都可以針對Spring如何管理bean進行個性化訂製。

正如你所見,在bean準備就緒之前,bean工廠執行了若干啟動步驟。

我們對上圖進行詳細描述:

  1. Spring對bean進行實例化;
  2. Spring將值和bean的引用注入到bean對應的屬性中;
  3. 如果bean實現了BeanNameAware介面,Spring將bean的ID傳遞給setBean-Name()方法;
  4. 如果bean實現了BeanFactoryAware介面,Spring將調用setBeanFactory()方法,將BeanFactory容器實例傳入;
  5. 如果bean實現了ApplicationContextAware介面,Spring將調用setApplicationContext()方法,將bean所在的應用上下文的引用傳入進來;
  6. 如果bean實現了BeanPostProcessor介面,Spring將調用它們的post-ProcessBeforeInitialization()方法;
  7. 如果bean實現了InitializingBean介面,Spring將調用它們的after-PropertiesSet()方法。類似地,如果bean使用initmethod聲明了初始化方法,該方法也會被調用;
  8. 如果bean實現了BeanPostProcessor介面,Spring將調用它們的post-ProcessAfterInitialization()方法;
  9. 此時,bean已經準備就緒,可以被應用程式使用了,它們將一直駐留在應用上下文中,直到該應用上下文被銷毀;
  10. 如果bean實現了DisposableBean介面,Spring將調用它的destroy()介面方法。同樣,如果bean使用destroy-method聲明了銷毀方法,該方法也會被調用。

現在你已經了解了如何創建和載入一個Spring容器。但是一個空的容器並沒有太大的價值,在你把東西放進去之前,它裡面什麼都沒有。為了從Spring的DI(依賴注入)中受益,我們必須將應用對象裝配進Spring容器中。

1.3 俯瞰Spring風景線

正如你所看到的,Spring框架關注於通過DI、AOP和消除樣板式程式碼來簡化企業級Java開發。即使這是Spring所能做的全部事情,那Spring也值得一用。但是,Spring實際上的功能超乎你的想像。

在Spring框架的範疇內,你會發現Spring簡化Java開發的多種方式。但在Spring框架之外還存在一個構建在核心框架之上的龐大生態圈,它將Spring擴展到不同的領域,例如Web服務、REST、移動開發以及NoSQL。

首先讓我們拆開Spring框架的核心來看看它究竟為我們帶來了什麼,然後我們再瀏覽下Spring Portfolio中的其他成員。

1.3.1 Spring模組

這裡只簡單介紹Spring模組,具體的可以查看Spring模組組成(框架組成、整體架構、體系架構、體系結構)

Spring 總共大約有 20 個模組, 由 1300 多個不同的文件構成。 而這些組件被分別整合在核心容器(Core Container) 、 AOP(Aspect Oriented Programming)和設備支援(Instrmentation) 、數據訪問與集成(Data Access/Integeration) 、 Web、 消息(Messaging) 、 Test等 6 個模組中。 以下是 Spring 5 的模組結構圖:

1.3.2 Spring Portfolio

當談論Spring時,其實它遠遠超出我們的想像。事實上,Spring遠不是Spring框架所下載的那些。如果僅僅停留在核心的Spring框架層面,我們將錯過Spring Portfolio所提供的巨額財富。整個Spring Portfolio包括多個構建於核心Spring框架之上的框架和類庫。概括地講,整個Spring Portfolio幾乎為每一個領域的Java開發都提供了Spring 編程模型

或許需要幾卷書才能覆蓋Spring Portfolio所提供的所有內容,這也遠遠超出了本書的範圍。不過,我們會介紹Spring Portfolio中的一些項目,同樣,我們將體驗一下核心框架之外的另一番風景。

Spring Portfolio主要包括如下項目,這裡不一一介紹Spring Web Flow,Spring Web Service,Spring Security,Spring Integration,Spring Batch,Spring Data,Spring Social,Spring Mobile,Spring for Android,Spring Boot等,感興趣的小夥伴可以自行研究。

Spring Security

安全對於許多應用都是一個非常關鍵的切面。利用Spring AOP,Spring Security為Spring應用提供了聲明式的安全機制。

Spring Integration

許多企業級應用都需要與其他應用進行交互。Spring Integration提供了多種通用應用集成模式的Spring聲明式風格實現。

Spring Data

Spring Data使得在Spring中使用任何資料庫都變得非常容易。儘管關係型資料庫統治企業級應用多年,但是現代化的應用正在認識到並不是所有的數據都適合放在一張表中的行和列中。一種新的資料庫種類,通常被稱之為NoSQL資料庫,提供了使用數據的新方法,這些方法會比傳統的關係型資料庫更為合適。

不管你使用文檔資料庫,如MongoDB,圖資料庫,如Neo4j,還是傳統的關係型資料庫,Spring Data都為持久化提供了一種簡單的編程模型。這包括為多種資料庫類型提供了一種自動化的Repository機制,它負責為你創建Repository的實現。

Spring Boot

Spring極大地簡化了眾多的編程任務,減少甚至消除了很多樣板式程式碼,如果沒有Spring的話,在日常工作中你不得不編寫這樣的樣板程式碼。Spring Boot是一個嶄新的令人興奮的項目,它以Spring的視角,致力於簡化Spring本身

Spring Boot大量依賴於自動配置技術,它能夠消除大部分(在很多場景中,甚至是全部)Spring配置。它還提供了多個Starter項目,不管你使用Maven還是Gradle,這都能減少Spring工程構建文件的大小。

1.4 Spring的新功能

當本書的第3版交付印刷的時候,當時Spring的最新版本是3.0.5。那大約是在3年前,從那時到現在發生了很多的變化。Spring框架經歷了3個重要的發布版本——3.1、3.2以及現在的4.0——每個版本都帶來了新的特性和增強,以簡化應用程式的研發。Spring Portfolio中的一些成員項目也經歷了重要的變更。

本書也進行了更新,試圖涵蓋這些發布版本中眾多最令人興奮和有用的特性。但現在,我們先簡要地了解一下Spring帶來了哪些新功能。

這裡就不介紹Spring 3.0的新特性了,因為Spring 5.0都出來了,舊版本的新特新就沒有多大必要介紹了。

1.4.1 Spring 3.1新特性

1.4.2 Spring 3.2新特性

1.4.3 Spring 4.0新特性

當編寫本書時,Spring 4.0是最新的發布版本。在Spring 4.0中包含了很多令人興奮的新特性,包括:

  • Spring提供了對WebSocket編程的支援,包括支援JSR-356——Java API for WebSocket;
  • 鑒於WebSocket僅僅提供了一種低層次的API,急需高層次的抽象,因此Spring 4.0在WebSocket之上提供了一個高層次的面向消息的編程模型,該模型基於SockJS,並且包含了對STOMP協議的支援;
  • 新的消息(messaging)模組,很多的類型來源於Spring Integration項目。這個消息模組支援Spring的SockJS/STOMP功能,同時提供了基於模板的方式發布消息;
  • Spring是第一批(如果不說是第一個的話)支援Java 8特性的Java框架,比如它所支援的lambda表達式。別的暫且不說,這首先能夠讓使用特定的回調介面(如RowMapper和JdbcTemplate)更加簡潔,程式碼更加易讀;
  • 與Java 8同時得到支援的是JSR-310——Date與Time API,在處理日期和時間時,它為開發者提供了比java.util.Date或java.util.Calendar更豐富的API;
  • 為Groovy開發的應用程式提供了更加順暢的編程體驗,尤其是支援非常便利地完全採用Groovy開發Spring應用程式。隨這些一起提供的是來自於Grails的BeanBuilder,藉助它能夠通過Groovy配置Spring應用;
  • 添加了條件化創建bean的功能,在這裡只有開發人員定義的條件滿足時,才會創建所聲明的bean;
  • Spring 4.0包含了Spring RestTemplate的一個新的非同步實現,它會立即返回並且允許在操作完成後執行回調;
  • 添加了對多項JEE規範的支援,包括JMS 2.0、JTA 1.2、JPA 2.1和Bean Validation 1.1。

1.4.4 Spring 5.0新特性

Spring 5.0是在2013年發布Spring 4後的第一個大版本,5.0 M1在2016年7月28日發布。隨著慢慢的推廣,使用它的人數肯定也會越來越多,那麼Spring 5有哪些新的特性呢?一起來看下吧

基本可以歸為如下幾類:

  • JDK版本升級
  • Core框架修訂,核心容器更新
  • Kotlin函數式編程
  • 響應式編程模型
  • 測試改進
  • 額外庫支援
  • 停止維護一些特性

可以看到,在Spring框架的最新發布版本中,包含了很多令人興奮的新特性。在本書中,我們將會看到很多這樣的新特性,同時也會學習Spring中長期以來一直存在的特性。

1.5 小結

現在,你應該對Spring的功能特性有了一個清晰的認識。Spring致力於簡化企業級Java開發,促進程式碼的鬆散耦合。成功的關鍵在於依賴注入和AOP

在本章,我們先體驗了Spring的DI。DI是組裝應用對象的一種方式,藉助這種方式對象無需知道依賴來自何處或者依賴的實現方式。不同於自己獲取依賴對象,對象會在運行期賦予它們所依賴的對象。依賴對象通常會通過介面了解所注入的對象,這樣的話就能確保低耦合。除了DI,我們還簡單介紹了Spring對AOP的支援。AOP可以幫助應用 將散落在各處的邏輯彙集於一處——切面。當Spring裝配bean的時候,這些切面能夠在運行期編織起來,這樣就能非常有效地賦予bean新的行為。

依賴注入和AOP是Spring框架最核心的部分,因此只有理解了如何應用Spring最關鍵的功能,你才有能力使用Spring框架的其他功能。在本章,我們只是觸及了Spring DI和AOP特性的皮毛。在以後的幾章,我們將深入探討DI和AOP。

本文由來源 ThinkWon的部落格,由 system_mush 整理編輯,其版權均為 ThinkWon的部落格 所有,文章內容系作者個人觀點,不代表 Java架構師必看 對觀點贊同或支援。如需轉載,請註明文章來源。