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() );
}
}