1. 程式人生 > >spring中的兩大核心模組:IOC和AOP

spring中的兩大核心模組:IOC和AOP

Spring就像一個管家,幫你管理事務。傳統的應用,應用層(Struts2)和事務層(Service)聯絡很緊密,通過Spring管理之間的關係,減低其耦合性。Spring的出現就是為了解決現有問題,使開發更快捷,更健壯。另外,一定要好好學習Spring,他可是有一統天下的野心。有針對Struts2的SpringMVC,有針對Hibernate/mybatis的SpringData,以及為了簡化開發的 Spring boot 和 Spring Cloud。

第一章:控制反轉和容器

IOC:Inversion of Control

DI:Dependency Injection

EJB:Enterprise JavaBeans

服務定位器:Service Locator

IoC的設計原則被許多容器用來解耦元件之間的依賴關係,spring framework提供了一個強大、可擴充套件的IoC容器來管理元件。

傳統:在提到Java EE平臺的元件時,會想到EJB。EJB規範明確的定義了EJB元件和EJB容器之間的契約。優點:只要執行在EJB容器裡,EJB元件就能獲得生命週期的管理、事務管理以及安全服務等諸多好處;缺點:元件不能脫離EJB容器執行,解耦元件之間的依賴很難,太複雜,被稱為重量級元件

現在:IoC是輕量級元件,而且被證明很有效。

IoC是一個通用的設計原則,DI則是具體的設計模式,DI是IOC最典型的事務實現,IOC和DI兩術語之間會混用。

 

下面三條可以簡單的說明IoC的底層實現:

1.1使用容器管理元件

問題:面向物件基本思想是將系統分解成一組可重用的物件。如果沒有一個核心模組來管理這些物件,它們將不得不各自建立和管理自己的依賴,結果就是這些物件會緊緊地耦合在一起。

方案:需要一個容器來管理組成系統的物件。該容器集中建立物件,並以登錄檔的形式提供物件的查詢服務;同時,該容器還要管理物件的生命週期,併為這些物件提供一個服務平臺。運行於容器裡的物件被稱為元件,它們必須要遵循容器所定義的規範。一個功能齊全的容器會很複雜。

實現:

1.2使用服務定位器降低查詢元件的複雜性

問題:在容器的管理下,元件之間的依賴僅僅是介面依賴,而不是實現依賴。然而,它們還是要用複雜的私有程式碼

從容器裡查詢自己所需要的元件。

方案:要降低查詢元件的複雜性,可以使用Sun的Java EE核心模式——服務定位器。這個模式的思想是,儘量使用服務定位器來封裝複雜的查詢邏輯,同時對外公開簡單的查詢方法,然後所有元件都可以將查詢請求委派給該服務定位器。

1.3應用控制反轉和依賴注入

問題:當元件需要外部資源(資料來源或對其他元件的引用)時,最直接也最明智的方法是執行查詢,這裡成為主動查詢。儘管使用了服務定位器來封裝查詢邏輯,這種查詢依舊存在缺點——元件需要知道如何獲取資源。

方案:應用IoC,它的思想是反轉資源獲取的方向:傳統的資源查詢方式要求元件自己想容器發出請求來查詢資源,容器再適時地返回資源(主動查詢);應用IoC後,容器主動地將資源推送到它所管理的元件裡,元件所要做的僅僅是選擇一種合適的方式來接收資源(被動查詢)。在DI模式裡,容器以一些預先定義好的方式(如通過setter方法)將匹配的資源注入到每個元件裡。

IOC原則類似於好萊塢那句低聲下氣的廣告語——“你別來找我,我會去找你的”(Don’t call us,we’ll call you),所以在程式設計模式中,IoC原則也被稱為“好萊塢原則”。

1.4主要有三種依賴注入(DI):

1、介面注入(Type 1 IoC)☆

   所有元件必須要實現特定的介面,介面特定於容器,導致元件對容器產生依賴(不用)

2、setter注入(Type 2 IoC)☆☆☆ 

在每個元件例項化之後,容器呼叫元件的setter方法注入依賴

ReportService reportService = new ReportService();

reportService.setReportGenerator(reportGenerator);

       此種很流行,大多數Java IDE都支援setter方法的自動生成。

缺點:使用者忘記注入依賴,導致NullPointException異常,Spring IoC容器這種高階的會提供檢查;第一次注入後,可能會再次呼叫setter導致再次注入,這種無意修改會產生無法預料的後果。

3、構造器注入(Type 3 IoC)☆☆

       解決了setter注入的兩大缺點,但它沒有含義明確的方法名,有時候必須參考相關javadoc,降低了程式碼可讀性。

每個元件例項化的時候,容器將依賴作為構造器的引數傳入元件的構造器。

在容器中,要顯示的建立一個預設的構造器。

ReportService reportService = new ReportService(reportGenerator);

1.5使用配置檔案配置容器

問題:為了讓容器能夠管理元件以及元件之間的依賴,前期必須以正確的資訊配置容器。但如果使用Java程式碼配置則每次修改配置之後都必須重新編譯原始碼(效率極低)!

方案:使用基於文字的、可讀性強的配置檔案。屬性檔案或者XML檔案,它們不需要重新編譯,如果要經常去改動配置,他們更有效。

XML比較強大,簡單容器屬性檔案就可以了。要將先前的程式設計配置改為基於屬性的配置,需要建立components.properties檔案,其中:

新元件定義:使用元件名字作為鍵,全限定類名作為值。

依賴注入:結合元件名和屬性名,中間是“.”,構成鍵;(在組建類裡必須為這個屬性定義setter方法),值是另外被注入的元件的引用名。

 

2、Spring簡介=Spring Framework概要介紹

 

Spring採用分級方式,在架構上劃分為多個模組,我們主要學習模組的功能。

Spring不僅是一個涉及內容廣泛的Java/Java EE應用程式框架,也是一個平臺,擁有許多與之相關的開源專案---->Spring Portfolio專案。

使用spring framework開發java/java ee應用程式。

a.Spring Framework的安裝,瞭解spring的安裝目錄結構,及目錄下的具體內容;

b.Spring專案Spring IDE是一個Eclipse外掛,簡化spring應用程式的開發。

2.1 Spring Framework的核心是輕量級的IoC容器,能為簡單的Java物件增加企業及服務;

   Spring通過AOP這種優秀的程式設計方式,為它的元件提供企業及服務;

   Spring IoC容器的作用範圍裡,元件也稱為Bean

 

2.2 可以通過安裝spring portfolio專案Spring IDE來開發spring專案(應用程式)。

 

 

3.Spring IoC中基本元件(bean)配置

POJO:Plain Old Java Object 普通的Java物件/JavaBeans

 

Spring裡元件也被稱為Bean,可以是任意的POJO。

POJO可以用來作為支援業務邏輯的協助類;可理解為簡單的實體類,方便程式設計師使用資料庫中的資料表;POJO物件有時也被稱為Data物件,在Hibernate/MyBatis框架中,使用物件和資料庫中的表對應,物件的屬性與表中的欄位對應。

 

 

3.1spring IoC中配置Bean

問題:

Spring提供了強大的IoC容器來管理來管理組成應用程式的Bean。要利用容器提供服務,就必須配置Bean,讓Bean執行在Spring IoC容器裡。

方案:Spring IoC中可通過XML檔案、屬性檔案甚至API來配置Bean。XML檔案比較簡單成熟。Spring允許使用一個或多個Bean配置檔案來配置Bean。

 

3.2例項化spring IoC容器

問題:

在spring IoC容器讀取Bean配置建立Bean例項之前,必須對它進行例項化。只有在容器例項化之後,才可以從IoC容器裡獲取Bean例項並使用它們。

方案:spring提供兩種型別的IoC容器實現:Bean Factory(基礎實現)、Application Context(高階實現)。後者是對前者的擴充套件,而且Bean配置檔案是相同的。Bean Factory的介面BeanFactory是Application Context介面ApplicationContext的父介面。

 

 

 

Spring AOP使用代理設計模式來作為底層實現原理

5動態代理和經典的Spring AOP

AOP:aspect-orient programming 面向切面程式設計

GoF:Gang of Four 設計模式

OOP:object-orient programming 面向物件程式設計

crosscutting concern:橫切關注點,跨越應用程式多個模組的功能和需求,企業應用:日誌、驗證和事務管理。

 

AOP是一種新的方法論,它是對傳統的OOP的補充。AOP和OOP經常一起使用。

 

在OOP世界裡,應用程式通過類和介面組織

——優點:這些程式設計元素非常適合實現核心的業務需求;缺點:對於橫切關注點不行,橫切關注點在企業應用程式裡非常普遍。

AOP世界裡,為開發者提供了另一種組織應用程式結構的方式。不再是OOP裡的類和介面,而是切面這種程式設計元素。

 

橫切關注點的模組化很難通過傳統的面向物件的方式模組化:

類比:AOP切面模組化橫切關注點,OOP類模組化狀態和行為。

 

三種主流的開源AOP框架:AspectJ、JBoss AOP、Spring AOP

AspectJ是Java社群最完整最流行的AOP框架;Spring AOP也比較完整,主要目的給Spring IoC容器提供一種一致性整合的AOP解決方案,它只能處理宣告在IoC容器裡的Bean的橫切關注點。

 

AOP的核心實現技術是:動態代理。

 

5.1非模組化的橫切關注點所帶來的問題

橫切關注點是指跨越應用程式多個模組的功能。

1、追蹤方法:大多應用程式都有一個通用的需求,即在程式執行期間追蹤正在發生的活動。在Java平臺上,有多個可供選擇的日誌實現。

如果希望應用程式和具體的日誌實現無關聯,Apache Commons Logging庫比較適合,他提供了與實現無關的抽象API,不用修改程式碼即可在不同的日誌實現之間進行切換。

可以用來記錄方法的開始和結束,還可以記錄方法的引數和返回值。

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

....

private Log log = LogFactory.getLog(this.getClass);

....

log.info(“the method begin with” + a);

....

你可以自由的選擇Commons Logging庫所支援的日誌實現。目前它主要支援Apache的Log4J庫和JDK Logging API,最好選前者,它更好配置。

Log4J支援6種日誌級別,用於設定日誌資訊的緊急程度。由高到低為fatal、error、warn、info、debug和trace。在Log4J配置檔案log4j.properties裡,可以設定應用程式的根(預設)日誌級別error,則意味著預設情況下只會輸出fatal和error級別的日誌資訊。也可以程式設計中手動設定。

       2、驗證引數(出現橫切關注點)

為方法制造一個引數約束:必須為正數。那麼每個方法的開始都需要呼叫validate()方法,如果為負數則丟擲IllegalArgumentException。

3、上面就暴露出一個問題:越來越多的非業務需求(日誌、驗證)加入後,業務方法的內容急劇膨脹。這些屬於系統範圍的需求通常需要跨越多個模組,所以為了將它們與核心業務區別開來,就把他們稱作橫切關注點

企業級應用程式中典型的橫切關注點包括:日誌、驗證(包括身份驗證)、快取、連線池和事務。

 

非模組化的橫切關注點導致兩個主要問題:

a.程式碼混亂(code tangling),每個方法在處理核心業務的時候還必須兼顧其他的關注點,這也會使得程式碼的可維護性和複用性變得很差。

       b.程式碼分散(code scattering),以日誌需求為例,為了滿足這單一的需求,就不得不在多個模組裡多次重複相同的程式碼;日誌需求發生變化,則必須修改所有模組,這很難保證日誌需求的一致性,若遺漏一處後果重大。

 

模組化橫切關注點的作用:將日誌和驗證關注點從核心業務中分離出來。

 

 

5.2使用動態代理模組化橫切關注點 (難度大)

問題:橫切關注點模組化

方案:用代理的設計模式將橫切關注點從核心業務離分離出來。

代理模式是23中GoF面向物件設計模式裡的一種,屬於“結構模式”。原理:使用一個代理將物件包裝起來,然後用該代理物件取代原始物件,任何對原始物件的呼叫首先都要經過代理。這也說明代理物件負責決定是否以及何時將方法呼叫轉發到原始物件上。而且圍繞著每個方法的呼叫,代理物件也可執行一些額外的任務。

在Java裡代理設計模式的實現的方法:

1.以純面向物件的方式編寫一個靜態代理;缺點:需要使用專門的代理包裝物件,意味著每個介面都需要編寫一個代理類(低效)。2.JDK動態代理,動態的為任意物件建立代理;缺點/限制:被代理的物件必須至少實現一個介面,並且只有呼叫那些宣告在接口裡的方法才會經過代理。3.動態代理的優化——CGLIB代理,克服2中的缺點,可以處理類中所有宣告的方法—可以不用實現任何介面。

實現:JDK動態代理模組化橫切關注點。核心包java.lang.reflect. InvocationHandler/Method/Proxy。建立日誌代理:建立一個具有呼叫處理程式的JDK動態代理例項,只需方法呼叫靜態方法Proxy.newProxyInstance(…);驗證代理,遍歷引數數目來驗證每個方法引數。

代理設計模式實現多個關注點——可以使用驗證代理包裝日誌代理形成一個代理鏈,方法得先經過驗證代理,再日誌代理。

5.3使用經典的Spring通知來模組化橫切關注點

問題:JDK動態代理太苛刻。

方案:對於橫切關注點,AOP定義了一組高層次的概念:執行點執行的橫切動作被封裝在通知(advice)裡。Spring AOP的4種通知型別,分別作用於執行點的不同時間。在正式的AOP定義裡,多種型別的執行點:方法執行、構造器執行、欄位訪問。但Spring AOP只支援方法執行。

       4種通知型別:前置通知(方法執行前)、返回通知(方法返回結果後)、異常通知(方法丟擲異常後)、環繞通知(圍繞方法執行)。

實現:Spring AOP只為在它的IoC容器裡宣告的Bean處理橫切關注點,所以在使用Spring AOP模組化橫切關注點之前,必須將應用程式遷移到Spring IoC容器裡——在spring的Bean配置檔案裡宣告應用程式即可。

6.1在spring中啟用AspectJ註解支援

問題:spring2.x支援在他的AOP框架中使用一Aspect註解編寫的POJO切面。但是,首先必須在Spring IoC容器裡啟用AspectJ註解支援。

方案:Bean配置檔案中定義控的XML元素:<aop:aspectj-autoproxy />即可

 

在apsectJ註解中,切面只是一個帶有@AspectJ註解的Java類。AspectJ支援5種類型的通知註解:@Before @After @AfterReturning @AfterThrowing和@Around

@Aspect

public class CalculatorLoggingAspect {

       private Log log = LogFactory.getLog(this.getClass());

       @Before(“execution (* ArithmeticCalculator.add(..))”)

       public void logBefore(JoinPoint joinPoint) { //訪問連線點

              log.info(“before”+joinPoint.getSignature().getName() );

       }

}