--- title: 'Spring Framework' disqus: hackmd --- Spring Framework === [TOC] ###### tags: `Spring` ## 概述 Overview ![](https://i.imgur.com/lYbHetV.png) * ### 簡介 介紹有關Spring Framework的核心概念以及功能說明,此篇不適合初學程式語言的人,需具備一定基礎的開發者閱讀。 Spring 框架是一個IoC (Inversion of Control)和AOP (Aspect-oriented programming)的構架多層J2EE系統的框架,採用IoC可以容易實現bean的配置,而AOP實現Transcation的管理,spring的好處是該框架不強迫你必須在系統的每一層都必須使用Spring,允許你根據自己的需要選擇使用它的某一個模塊;Spring優良的模組化,對不同的數據訪問技術提供了統一的介面規範。 Spring 框架的功能可以用在任何 J2EE 伺服器中,大多數功能也適用於不受管理的環境。Spring 的核心要點是:支援不綁定到特定 J2EE 服務的可重用業務和資料訪問物件。毫無疑問,這樣的物件可以在不同 J2EE 環境 (Web 或 EJB)、獨立應用程式、測試環境之間重用。Spring 框架是一個分層架構,由 8 個定義良好的模組組成(spring 4之後已更動過)。Spring 模組構建在核心容器之上,核心容器定義了創建、配置和管理 bean 的方式。 * ### 特色 低侵入 / 低耦合 (降低組件之間的耦合度,實現軟體各層之間的解耦) 聲明式事務管理(基於切面和慣例) 方便集成其他框架(如MyBatis、Hibernate) ## Spring 主要產品 Main Projects * Spring 是一個開放源代碼的設計層面框架,他解決的是業務邏輯層和其他各層的松耦合問題,因此它將面向接口的編程思想貫穿整個系統應用。 * Spring MVC 屬於SpringFrameWork的後續產品,已經融合在Spring Web Flow裡面。 Spring 框架提供了構建 Web 應用程序的全功能 MVC 模塊。 * Spring Task 是一個定時任務框架。應用:定時執行刷新Redis數據。定時執行刪除過期數據 * Spring Security 是一個能夠為基於Spring的企業應用系統提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉Inversion of Control ,DI:Dependency Injection 依賴注入)和AOP(面向切面編程)功能,為應用系統提供聲明式的安全訪問控制功能,減少了為企業系統安全控制編寫大量重複代碼的工作。 * Spring Data 是Spring 的一個子項目, 旨在統一和簡化對各類型持久化存儲, 而不拘泥於是關係型數據庫還是NoSQL 數據存儲。 * SpringDataSolr 是一個搜索解決方案,基於Lucene的搜索服務器。應用:站內產品搜索 * Spring Boot 是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。 * Spring Cloud 是一系列框架的有序集合。它利用Spring Boot的開發便利性巧妙地簡化了分佈式系統基礎設施的開發,如服務發現註冊、配置中心、消息總線、負載均衡、斷路器、數據監控等,都可以用Spring Boot的開發風格做到一鍵啟動和部署。 * Spring Web Flux是Spring Framework 5.0中引入的Reactive Web框架,名稱中的 Flux 來源於 Reactor中的Flux。該模塊中包含了Reactive HTTP、Server推送事件和 WebSocket 的Client端和Server端的支持。對於開發人員來說,比較重要的是Server端的開發。 與Spring MVC不同,它不需要Servlet API,完全非同步和非阻塞, 並通過Reactor實現Reactive Streams規範,所以性能更高。 並且可以在諸如Netty,Undertow和Servlet 3.1+容器的服務器上運行。 ## 模組 Modules ### Spring 模組結構圖 ##### Spring 4去掉在Spring 3 Web層的Struts,並添加了Websocket跟Messaging,其他模組維持不變。 ![](https://i.imgur.com/6CPUHiI.png) ### 八大模塊 十九個模組 這裡整理後分別為Core, AOP ,Data Access/Integration, Web, Aspects, Instrumentation, Messaging, Test * **Core container** 1. Core : 提供了框架的基本組成部分,包括 IoC 及 依賴注入 功能。 1. Beans:實現 Bean 管理,包括自動裝配機制等功能; 其中BeanFactory是一個工廠模式的實現。 1. Context:建立在 Core 和 Bean 模組基礎上,通常用於訪問配置及定義的任何物件。ApplicationContext 是上下文模組的重要介面。 1. SpEL:表示式語言模組提供了執行時進行查詢及操作一個物件的表示式機制。 * **Data Access/Integration** 1. JDBC:用於替代繁瑣的 JDBC API 的抽象層。 1. Transaction:事務模組為各種 POJO 支援程式設計式和宣告式事務管理。 1. ORM:物件關聯式資料庫對映抽象層,可整合JPA,JDO,Hibernate,iBatis等等。 1. OXM:XML訊息繫結抽象層,支援JAXB,Castor,XMLBeans,JiBX,XStream。 1. JMS:Java訊息服務模組,實現訊息生產-消費之類的功能。 * **Web** 1. WebMVC:(SpringMVC) 提供了基於 模型-檢視-控制器 的基礎web應用框架。 1. Servlet:實現了統一的監聽器以及和面向web應用的上下文,用以初始化 IoC 容器。 1. Portlet:實現在 portlet 環境中實現 MVC。 1. Socket:為 WebSocket 連線 提供支援。 * **AOP** 切面導向程式設計,通過預編譯方式和執行時期動態代理實現功能統一維護的一種技術。 * **Aspects** 提供了與 AspectJ 的整合,這是一個功能強大且成熟的面向切面程式設計(AOP)框架。 * **Instrumentation** 實現instrumentation支援,一般用以應用伺服器的監測。 * **Messaging** 為 STOMP 提供了支援,STOMP 協議是一種簡單的文字定向訊息協議,是 WebSocket 的子協議。 * **Test** 支援 JUnit 、TestNG 框架的整合。 > 備註:不同版本JAR包依賴會有所區別 > [*Spring Framework體系結構及模塊jar依賴關係詳解*](https://www.jb51.net/article/168989.htm) > ## 核心容器 core container Spring的核心容器,實作了IoC的概念,是一個輕量級容器,功能面而言又稱為「IoC Container」 核心容器(Core Container)內的 **Core模組** 、 **Beans模組** ,提供spring架構的最基本功能,構成Core Container的主體,其中的主要元件是BeanFactory,它是Factory Pattern的複雜實作。 > 延伸閱讀 > [*簡單工廠模式 Simple Factory Pattern*](https://skyyen999.gitbooks.io/-study-design-pattern-in-java/content/simpleFactory.html) > [*工廠模式 Factory Pattern*](https://skyyen999.gitbooks.io/-study-design-pattern-in-java/content/factory.html) > [*策略模式 Strategy Pattern*](https://skyyen999.gitbooks.io/-study-design-pattern-in-java/content/strategy.html) > [*模板方法模式 Template Method Pattern*](https://blog.51cto.com/liukang/2048245) ### 控制反轉 Inversion of Control 控制反轉(Inversion of Control,縮寫為IoC),是物件導向程式設計中的一種設計原則,可以用來降低程式之間的耦合度。對於spring框架來說,就是由spring來負責控制對象的生命週期和對象間的關係。 其中最常見的方式叫做**依賴注入(Dependency Injection,簡稱DI)**,還有一種方式叫**Service Locator**。 > Service Locator > [*Inversion of Control Containers and the Dependency Injection pattern*](https://martinfowler.com/articles/injection.html) 我們假設一個場景:Person(人)每天都要吃早餐(食物)。我們可以用以下程式表示 ```java= public class Person { public void eat() { Food food = new food(); System.out.println("I eat food:{}", food.toString()); } } ``` 在我們吃飯之前必須先new food()(做飯),要不然就吃不上。 IoC 會怎麼樣做呢 ```java= public class Person { private Food food; public void eat() { System.out.println("I eat food:{}", food.toString()); } } ``` 它會在你吃的時候將食物準備好,不需要你自己做飯。因為它認為:吃飯的人不應該身兼廚師的角色。借用《spring 揭秘》中的漫畫再說明一下吧。它的意思是:穿衣服出門。如果不使用IoC,你就得自己去取衣服穿上。用了IoC,已經有美女給你拿過來並幫你穿上。 IoC就是讓你當大爺,你只需要發揮自己的特長就可以了,其它的讓小秘書來幫你完成。 ![](https://i.imgur.com/rboSegT.png) > 延伸閱讀 > [*物件導向設計原則—SOLID*](https://ithelp.ithome.com.tw/articles/10191553) > [*依賴倒置原則*](https://notfalse.net/1/dip) ### 依賴注入 Dependency Injection 依賴注入(Dependency Injection,縮寫為DI),目的就是為了把IoC的概念以更明確的方式呈現,兩者關係密不可分,IoC就是透過DI來實現的。 實現DI的有兩種形式: 1. 建構子注入 (Constructor Injection) 1. Setter方法注入 (Setter Injection) 1. 介面注入 (Interface Injection) ```java= public class John implements Person { private Phone phone; // 建構子注入 (Constructor Injection) public John(Phone phone) { this.phone = phone; } // Setter方法注入 (Setter Injection) public void setPhone(Phone phone) { this.phone = phone; } // Interface介面注入 (Interface Injection) @Override public void phoneInject(Phone phone) { if(phone != null) phone.call(); } ``` 框架幫管理了所有瑣事。 ## AOP 切面導向程式設計 AOP為Aspect Oriented Programming的縮寫,意為:切面導向程式設計,通過預編譯方式和執行時期動態代理實現功能統一維護的一種技術。 AOP是OOP的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。 ### **AOP基本概念** * 在一個應用程的主要服務,(業務or商務)流程中,有時要插入一些與主服務流程本身無關的系統考量邏輯,例如: Logging、Security、Transation、Exception...等,這些插入的系統考量邏輯稱之為,**Cross-cutting concerns(橫切關注點)(橫跨性關注)** * 如果沒有仔細切分,容易造成程式碼中原本的主服務流程和系統考量交雜在一起,造成程式難以維護。 * 基於重用(Reuse)原則,可以將Crossing-cutting concerns獨立出來成為一個物件,這個物件稱之為Aspect(切面) * 開發完成後再一次套用Aspect(切面),在所有具有此需求的業務流程 * AOP(Aspect-oriented programming)著重在Aspect的設計及應用程式之間的Weave(縫合)。 ### **AOP相關術語** * #### Cross-cutting concerns(橫向關注點) ![](https://i.imgur.com/aNERc1S.jpg) * #### JointPoint(連接點) JointPoint 是在主業務流程中,程式執行過程的一個執行點(包括靜態或動態執行點),例如某個方法被呼叫,某個成員被存取,或是某個例外被拋出,或到最複雜的動態控制流程...等執行點。 他是一個抽象的概念,在實現AOP時,並不需要去定義一個JoinPoint。 * #### PointCut(切入點) PointCut是JoinPoint的集合,我們可以利用PointCut將JoinPoints集合起來,因此PointCut是指示一個Aspect該編織到哪些應用程式的那些地方的最主要之依據。 ![](https://i.imgur.com/ypMfwY3.jpg) 在Spring2.0後(含),PointCut的定義包含兩個部分: PointCut **表示式(expression)** 和 PointCut **簽名(Signature)** * #### Advice(通知、建議) Advice定義在特映的JoinPoint(連接點)上要執行的程式碼(Logging、Security、Transation...等) 每個Advice都需要一個PointCut作為依據 Advices實作了Aspect的真正邏輯,在Java中具體來說就是一個類別,或更細粒度的設計為一個方法(由一個類別來基中管理許多Advices) 由於縫合至Target的時機不同,Spring提供了幾種不同的Advices,其中包含了「before」、「after」、「around」等不同型別的通知。 **1. Before advice (前置通知)** 在某個JoinPoint(連接點)之前執行的通知 **2. After returning(後置通知)** 在某JoinPoint(連接點)正常完成後執行的通知(例如:一個方法沒有拋出任何異常,正常返回) **3. After throwing advice(異常通知)** 在方法拋出異常對初時執行的通知 **4. After (finally) advice(最終通知)** 當某JointPoint(連接點)退出的時候執行的通知(無論是正常返回還是異常退出) **<font color="red">5. Around advice (環繞通知)</font>** 環繞通知可以在方法呼叫前後完成自定義的行為。它也可以選擇是否繼續執行JointPoint(連接點),或直接回傳它自己的回傳,或拋出異常時來結束執行。 Before advice與After advice 不會影響在PointCut內所選到的方法的執行。 但Around Advice不同,可以選擇取代Jointpoint的執行或是修改執行的結果。 在Around Advice(環繞通知)執行中,是以透過呼叫ProceedingJoinPoint的Proceed()方法來執行原來被擱置的JoinPoint的方法。 ##### 在真正呼叫proceed()方法之前,目標物件的方法並不會被執行,而proceed()方法執行完畢後傳回一個物件,表示目標物件的方法執行完畢後的傳回值,在Around Advice方法執行完畢後可以傳回這個物件,甚至傳回另一個物件。 * #### Target Object(目標物件) Target Object(目標物件)是被一個或者多個Aspects切面,所通知的物件,所以此物件也被稱作通知(advised)物件。 由於Spring AOP的實作是使用動態代理,所以這個物件永遠是一個被代理(proxied)物。 * #### Introduction(引入) 對於一個現存的類別,Introduction可以為期增加行為,而不用修改該類別的程式,具體的說,您可以為某個以撰寫、編譯完成的類別,在執行時期動態加入一些方法或行為,而不用修改或新增任何一行程式碼。 * #### AOP proxy(AOP代理) 這是AOP框架(framework)創建出一個物件,用來實作Aspect contracts(切面契約 例:advice 方法執行等等)在spring中,AOP代理可以是JDK動態代理(JDK dynamic proxy)或者CGLIB代理(CGLIB proxy) 在JDK1.3之後加入了可協助開發動態代理功能的API等相關類別,您不必為特定物件與方法撰寫特定的代理物件,使用動態代理,可以使得一個處理者(Handler)服務於各個物件。 **SpringAOP**預設主要是透過,動態代理(dynamic proxies)來完成,這樣任何界面(或set of interface)都可以被代理。業務物件(bussiness object)通常都會實作一個或多個介面,這才是好的做法 雖然Spring也可以使用CGLIB代理,以用代理類別。也就是說如果一個業務物件(bussiness object)並沒有實作一個介面。才會使用CGLIB為Target產生一個子類別作為代理類別(Proxy classes)。 (未完待續...) ## *參考文獻 Reference Documentation* * [*Spring Framework Reference Documentation*](https://docs.spring.io/spring/docs/4.3.24.RELEASE/spring-framework-reference/html/index.html) * [*維基百科 wiki Spring Framework*](https://zh.wikipedia.org/wiki/Spring_Framework) * [*spring framework 模組簡介*](https://www.itread01.com/p/866734.html) * [*IoC-spring 的灵魂(带你轻松理解IOC思想及bean对象的生成过程)*](https://juejin.im/post/593386ca2f301e00584f8036)