Spring學習筆記2——高級特性

1.經過PropertyPlaceholderConfigurer在Spring中加載其餘外部配置文件或者屬性文件:html

在不少javaEE工程中,Spring的角色很是重要,是一個管理其餘模塊和組件的輕量級容器,Spring常常須要管理Struts、Ibatis、Hibernate等,這些開源框架的配置文件就經過Spring的PropertyPlaceholderConfigurer加載在Spring中進行管理,另外,數據庫鏈接信息、JNDI鏈接信息屬性文件等也能夠經過PropertyPlaceholderConfigurer加載到Spring中來管理。用法以下:java

(1).經過PropertyPlaceholderConfigurer將其餘文件加載到Spring中:node

在spring配置文件中添加以下配置:web

 

[xhtml] view plain copy print?spring

  1. <bean class=「org.springframework.beans.factory.config.PropertyPlaceholderConfigurer「>  
  2.        <property name=「locations「>  
  3.               <value>classpath:要加載的文件名</value>  
  4.               ……  
  5.        </property>  
  6. </bean>  

<bean class=「org.springframework.beans.factory.config.PropertyPlaceholderConfigurer「> <property name=「locations「> <value>classpath:要加載的文件名</value> …… </property> </bean> 數據庫

 

(2).通過(1)中的配置要加載的配置或屬性文件就被加載到spring中,若是還須要在運行時使用加載進來的配置或數據文件的一些信息,如使用數據庫鏈接信息或者JNDI鏈接信息時,就可使用類型EL表達式的語法進行引用,例如:express

 

[xhtml] view plain copy print?apache

  1. <bean id=」dataSource」 destroy-method=」close」 class=」org.apache.common.dbcp.BasicDataSource」>  
  2.        <!--假設數據庫鏈接信息寫在外部屬性文件中,已經被spring加載-->  
  3.        <property name=」driverClassName」 value=」${driver}」/>  
  4.        <property name=」url」 value=」${url}」/>  
  5.        <property name=」username」 value=」${username}」/>  
  6.        <property name=」password」 value=」${password}」/>  
  7. </bean>  

<bean id=」dataSource」 destroy-method=」close」 class=」org.apache.common.dbcp.BasicDataSource」> <!--假設數據庫鏈接信息寫在外部屬性文件中,已經被spring加載--> <property name=」driverClassName」 value=」${driver}」/> <property name=」url」 value=」${url}」/> <property name=」username」 value=」${username}」/> <property name=」password」 value=」${password}」/> </bean> 編程

 

注意:也可使用<context:Property-Placeholderlocation=」classpath:要加載的文件名」/>設計模式

2.Java的動態代理:

Spring的面向切面編程(AOP)底層實現原理是動態代理,所以在學習面向切面編程以前必須先了解動態代理。

Java中動態代理應用很是普遍,動態代理是23中設計模式中很是經常使用的經典設計模式之一。動態代理的原理是,當要調用一個目標對象或者其方法時,系統並非直接返回目標對象,而是返回一個代理對象,經過這個代理對象去訪問目標對象或者目標對象的方法。

動態代理的簡單原理以下:

客戶端調用者——>代理對象——>被調用的目標對象。

當客戶端調用代理對象時,代理對象委派目標對象調用其業務方法。

動態代理分爲兩種,針對接口的動態代理和針對普通類的動態代理,java中的動態代理是真的接口的動態代理,cglib是針對普通類的動態代理,目標javaEE的依賴包和Spring的jar包中已經包含了cglib相關jar包,所以便可以對代理也能夠對普通類進行動態代理。

(1).java的針對接口動態代理:

Java中的動態代理只能針對接口進行動態代理,所以,目標對象必須實現接口,代理對象要實現目標對象的全部接口。工做流程以下:

a.      動態代理類編寫:

注意:動態代理必須實現InvocationHandler接口,同時實現如下方法:

 

[java] view plain copy print?

  1. Object invoke(Objectm代理實例,Method代理實例上調用的接口方法的Method 實例,Object[] 傳入代理實例上方法調用的參數值的對象數組);  

Object invoke(Objectm代理實例,Method代理實例上調用的接口方法的Method 實例,Object[] 傳入代理實例上方法調用的參數值的對象數組); 

 

安裝JDK的文檔說明,該方法做用是傳遞代理實例、識別調用方法的 java.lang.reflect.Method 對象以及包含參數的 Object 類型的數組。調用處理程序以適當的方式處理編碼的方法調用,而且它返回的結果將做爲代理實例上方法調用的結果返回。

b.      建立代理對象:

 

[java] view plain copy print?

  1. Proxy.newProxyInstance(類加載器, Class<?>[]接口數組,回調代理對象(通常是this))  

Proxy.newProxyInstance(類加載器, Class<?>[]接口數組,回調代理對象(通常是this)) 

 

當調用目標對象方法時,經過該方法建立目標對象的代理對象,代理對象會自動調用其invoke方法調用目標對象,並將調用結果返回。

(2).cglib針對普通java類動態代理:

cglib建立動態代理時,不要求目標類必須實現接口,其工做流程以下:

a.動態代理類編寫:

 

[java] view plain copy print?

  1. Enhancer  enhancer = new Enhancer();  
  2. //設置目標類的父類爲其自己  
  3. enhancer.setSuperclass(目標類對象.getClass());  
  4. //設置回調對象爲動態代理對象自己  
  5. enhancer.setCallback(this);  

Enhancer enhancer = new Enhancer(); //設置目標類的父類爲其自己 enhancer.setSuperclass(目標類對象.getClass()); //設置回調對象爲動態代理對象自己 enhancer.setCallback(this); 

 

b.實現MethodInterceptor接口:

實現如下方法:

 

[java] view plain copy print?

  1. Object intercept(Objectm代理實例,Method代理實例上調用的接口方法的Method 實例,Object[] 傳入代理實例上方法調用的參數值的對象數組,MethodProxy 方法代理實例);  

Object intercept(Objectm代理實例,Method代理實例上調用的接口方法的Method 實例,Object[] 傳入代理實例上方法調用的參數值的對象數組,MethodProxy 方法代理實例); 

 

注意:cglib不但能夠針對類動態代理,還能夠針對方法動態代理。

3.面向切面編程(AOP)的基礎概念:

以一個普通的java方法來舉例

 

[java] view plain copy print?

  1. public 返回類型 方法名(參數列表){ ——>環繞通知  
  2.        方法前處理代碼    ——>     前置通知  
  3. try{  
  4.        方法具體實現(方法體)…….  
  5.        方法後處理代碼    ——>     後置通知  
  6. }Catch(異常類型 e){  
  7.        異常處理……       ——>     例外通知  
  8. }finally{  
  9.        最後處理代理……       ——>     最終通知  
  10. }  
  11. }  

public 返回類型 方法名(參數列表){ ——>環繞通知 方法前處理代碼 ——> 前置通知 try{ 方法具體實現(方法體)……. 方法後處理代碼 ——> 後置通知 }Catch(異常類型 e){ 異常處理…… ——> 例外通知 }finally{ 最後處理代理…… ——> 最終通知 } } 

 

a.      橫切關注點:如上面5個通知的位置,在java對象中,能夠這些具備相似共同處理邏輯的位置加入如權限驗證、事物處理、日誌記錄等處理邏輯的對象稱爲橫切關注點,面向對象編程(OOP)的關注點是縱向將現實世界的事物抽象成編程的對象模型。而面向切面編程(AOP)的關注點是橫向的,它將編程對象模型中擁有相似處理邏輯的地方抽象出來造成切面,而編程對象中的處理邏輯就是橫切關注點。

b.      切面(Aspect):將橫切關注點抽象就造成切面,與類相似,兩者關注點不一樣,類是事物特性的抽象,切面是橫切關注點的抽象。

c.      鏈接點(Joinpoint):被攔截到的點,在Spring中指方法,由於spring只支持方法類型的鏈接點,即被攔截的方法。如上面例子的方法。

d.      切入點(Pointcut):指對鏈接點進行攔截的定義,是鏈接點的集合,即一系列被攔截方法的集合。

e.      通知(Advice):指攔截到鏈接點以後要作的事情,即攔截以後的邏輯處理。一般的權限驗證、事物處理、日誌記錄等操做就是在通知中定義和完成的。

f.       目標對象(Target):代理的目標對象,即被攔截的對象。如上面例子中方法所在的對象。

g.      織入(Weave):指將切面應用到目標對象,並致使代理對象建立的過程。

h.      引入(Introduction):在不修改代碼的前提下,引入能夠在運行期爲類動態的添加一些方法和字段。

1.      Spring中支持面向切面編程(AOP)的依賴包:

Spring解壓後目錄中的以下3個包:

lib/aspectj/aspectjweaver.jar

lib/aspectj/aspectjrt.jar

lib/cglib/cglib-nodep-2.1-3.jar

2.      在spring中使用面向切面編程(AOP)時,須要在spring配置文件中引入aop的命名空間,即添加以下的配置:

 

[xhtml] view plain copy print?

  1. xmlns:aop=」http://www.springframework.org/schema/aop」  
  2. 「http://www.springframework.org/schema/aop  
  3. http://www.springframework.org/schema/aop/spring-aop-2.5.xsd」  

xmlns:aop=」http://www.springframework.org/schema/aop」 「http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd」 

 

注意:Spring2.5之後提供兩種AOP方法,即基於xml配置文件方式和基於java註解方式。

若要使用註解方式的aop,須要在spring配置文件中添加以下的對象註解方式aop的支持:

 

[xhtml] view plain copy print?

  1. <aop:aspectj-autoProxy/>  

<aop:aspectj-autoProxy/> 

 

6.    JavaBean的包裝類——BeanWrapper:

Spring經過BeanWrapper類封裝一個javabean的行爲,能夠設置和獲取其屬性值,如:

 

[java] view plain copy print?

  1. BeanWrapper 包裝類對象 = BeanWrapperImpl(new 被包裝類());  
  2. 包裝類對象.setPropertyValue(「屬性名」,」屬性值」);  

BeanWrapper 包裝類對象 = BeanWrapperImpl(new 被包裝類()); 包裝類對象.setPropertyValue(「屬性名」,」屬性值」); 

 

經過這種方法就能夠給被包裝類設置屬性。

7. 基於註解方式的面向切面編程(AOP)開發:

(1).在spring配置文件中加入對註解方法的aop支持。

(2).定義切面:

和建立普通類相似,在類前加上」@Aspect」註解,代表該類是一個切面。

(3).在切面中加入切入點:

切入點就是被攔截對象方法的集合,一般切入點定義在切面中某個對切入點進行處理的方法上。使用」@Pointcut」註解,語法以下:

 

[java] view plain copy print?

  1. @Pointcut(「execution(* com.test.service..*.*(..))」)  
  2. public void anyMethod(){//方法名爲切入點名  
  3. 切入點處理  
  4. }  

@Pointcut(「execution(* com.test.service..*.*(..))」) public void anyMethod(){//方法名爲切入點名 切入點處理 } 

 

語法參數詳解:

a. 第一個」*」:表示被攔截的方法是任意的返回類型。

b. com.test.service:這裏是舉一個簡單的例子,表示要被攔截的包名,即被攔截的包。

c.被攔截包名後面的兩個」..」:表示被攔截包下面的子包也遞歸進行攔截,即被攔截的子包。

d. 」..」以後的」*」:表示被攔截包及其子包下面的全部類,即被攔截的類。

e. 最後一個」*」:表示被攔截類中的全部方法,即被攔截的方法。

f. 」(..)」:表示被攔截的方法接收任意的參數,即被攔截的參數。

注意:切入點定義語法能夠支持通配符,可是必定要嚴格遵循語法規則。如:

@Pointcut(「execution(*com.test.service..*.add*(..))」)

表示對com.test.service包及其子包下全部的類中以」add」開頭的方法進行攔截。

(4).在切面中添加通知:

Spring中通知位置請參看3中的小例子。

」@Before」註解:聲明前置通知。

「@AfterRutruning」註解:聲明後置通知。

「@After」註解:聲明最終通知。

「@AfterThrowing」註解:聲明例外通知。

「@Around」註解:聲明環繞通知。

一個定義通知的例子以下:

 

[java] view plain copy print?

  1. @Before(「anyMethod()(切面中聲明的切入點名)」)  
  2. public void doAccessCheck(){  
  3.        ……  
  4. }  

@Before(「anyMethod()(切面中聲明的切入點名)」) public void doAccessCheck(){ …… } 

 

注意:環繞通知和其餘4種通知的稍有不一樣,環繞通知的定義方式比較特別,環繞通知在整個方法調用先後都會起做用,所以必須使用鏈接點對象告訴鏈接點在環繞通知處理以後繼續其邏輯處理。其定義方式以下:

 

[java] view plain copy print?

  1. @Around(切入點名)  
  2. public Object doBasicProfiling(ProcedingJoinPoint pjp) throws Throwable{  
  3.        ……  
  4.        return pjp.proceed();//該句是告訴鏈接點繼續執行其餘的操做  
  5. }  

@Around(切入點名) public Object doBasicProfiling(ProcedingJoinPoint pjp) throws Throwable{ …… return pjp.proceed();//該句是告訴鏈接點繼續執行其餘的操做 } 

 

7.      基於註解方式的面向切面編程(AOP)開發的一些小技巧:

(1).獲取輸入參數:

如:

 

[java] view plain copy print?

  1. @Before(「切入點名 && args(輸入參數名)」)  
  2. public void doSomething(String 輸入參數名){……}  

@Before(「切入點名 && args(輸入參數名)」) public void doSomething(String 輸入參數名){……} 

 

(2).獲取返回結果:

如:

 

[java] view plain copy print?

  1. @AfterReturning(Pointcut=」切入點名」,returning=」返回結果名」)  
  2. public void dosomething(String 結果名){……}  

@AfterReturning(Pointcut=」切入點名」,returning=」返回結果名」) public void dosomething(String 結果名){……} 

 

8.      基於XML方式的面向切面編程(AOP)開發:

(1).定義切面類,在切面類中添加通知。

(2).將切面類想普通java類同樣在spring配置文件中配置。

(3).在spring配置文件中添加AOP配置以下:

 

[xhtml] view plain copy print?

  1. <aop:config>  
  2.        <!--配置切面-->  
  3.        <aop:aspect id=」切面id」 ref=」spring配置文件中切面類的id」>  
  4.               <!--配置切入點-->  
  5.               <aop:pointcut id=」切入點id」  
  6. expression=」execution(* com.test.service..*.*(..))」/>  
  7.               <!--配置通知-->  
  8.               <aop:before pointcut-ref=」切入點id」 method=」切面類中相應的處理方法」/>  
  9.               <aop:after ……/>  
  10.               ……  
  11. </aop:aspect>  
  12. </aop:config>  

<aop:config> <!--配置切面--> <aop:aspect id=」切面id」 ref=」spring配置文件中切面類的id」> <!--配置切入點--> <aop:pointcut id=」切入點id」 expression=」execution(* com.test.service..*.*(..))」/> <!--配置通知--> <aop:before pointcut-ref=」切入點id」 method=」切面類中相應的處理方法」/> <aop:after ……/> …… </aop:aspect> </aop:config> 

 

9.      Spring的事務處理(Spring的聲明式事務處理):

事務簡單來講是指數據庫中的一條最基本的操做,關於事務的詳細講解之後會在數據庫相關總結中具體說明。Spring的面向切面編程(AOP)一個最重要的應用是事務管理,Spring2.5之後版本的事務管理支持基於註解的方式和基於XML文件的方式兩種:

(1).基於註解方式的事務管理:

a. 在spring配置文件中添加事務管理的命名空間以下:

 

[xhtml] view plain copy print?

  1. xmlns:ts=http://www.springframework.org/schema/tx  
  2. http://www.springframework.org/schema/tx  
  3. http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  

xmlns:ts=http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd 

 

b. 在spring配置文件中配置事務管理器以下:

 

[xhtml] view plain copy print?

  1. <bean id=」txManager」 class=」org.springframework.jdbc.datasource.DataSourceTransactionManager」>  
  2.        <property name=」dataSource」 ref=」spring中配置的數據源bean的id」/>  
  3. </bean>  

<bean id=」txManager」 class=」org.springframework.jdbc.datasource.DataSourceTransactionManager」> <property name=」dataSource」 ref=」spring中配置的數據源bean的id」/> </bean> 

 

c.      在spring配置文件中添加支持註解方式的事務配置項以下:

 

[xhtml] view plain copy print?

  1. <tx:annotation-driventransaction-managertx:annotation-driventransaction-manager=」txManager(spring中配置的事務管理器bean的id)」/>  

<tx:annotation-driventransaction-manager=」txManager(spring中配置的事務管理器bean的id)」/> 

 

d.      使用基於註解的事務管理:

在Spring所管理的JavaEE工程中,須要使用事務的業務邏輯地方加上「@Transactional」註解。

(2).基於XML文件方式的事務管理:

a. 在spring配置文件中配置事務管理器以下:

 

[xhtml] view plain copy print?

  1. <bean id=」txManager」 class=」org.springframework.jdbc.datasource.DataSourceTransactionManager」>  
  2.        <property name=」dataSource」 ref=」spring中配置的數據源bean的id」/>  
  3. </bean>  

<bean id=」txManager」 class=」org.springframework.jdbc.datasource.DataSourceTransactionManager」> <property name=」dataSource」 ref=」spring中配置的數據源bean的id」/> </bean> 

 

b.      在spring配置文件中添加事物管理的切面以下:

 

[xhtml] view plain copy print?

  1. <aop:config>  
  2.        <!--配置事務切入點-->  
  3.        <aop:pointcut id=」transactionPointcut」  
  4. Expression=」execution(* com.test.service..*.*(..))」/>  
  5. <!--配置事務通知-->     
  6. <aop:advisor advice-ref=」txAdvice」 pointcut-ref=」transactionPointcut」/>  
  7. </aop:config>  

<aop:config> <!--配置事務切入點--> <aop:pointcut id=」transactionPointcut」 Expression=」execution(* com.test.service..*.*(..))」/> <!--配置事務通知--> <aop:advisor advice-ref=」txAdvice」 pointcut-ref=」transactionPointcut」/> </aop:config> 

 

c.      在spring配置文件中爲事務通知添加事物處理特性以下:

 

[xhtml] view plain copy print?

  1. <tx:advice id=」txAdvice」 transactionManager=」txManager」>  
  2.        <tx:attributes>  
  3.               <!--這裏舉例將以get開頭的查詢方法設置爲只讀,不支持事務-->  
  4.               <tx:method name=」get*」 read-only=」true」 propagation=」NOT_SUPPORTED」/>  
  5.               <!--其餘的方法設置爲spring默認的事物行爲-->  
  6.               <tx:method name=」*」/>  
  7.        </tx:attributes>  
  8. </tx:advice>  

<tx:advice id=」txAdvice」 transactionManager=」txManager」> <tx:attributes> <!--這裏舉例將以get開頭的查詢方法設置爲只讀,不支持事務--> <tx:method name=」get*」 read-only=」true」 propagation=」NOT_SUPPORTED」/> <!--其餘的方法設置爲spring默認的事物行爲--> <tx:method name=」*」/> </tx:attributes> </tx:advice> 

 

10.  Spring與Struts1集成的3種方式:

(1).方式1——使用spring中對struts1請求控制器方式:

a. 在struts1的配置文件中添加以下配置:

 

[xhtml] view plain copy print?

  1. <controller>  
  2.        <set-property property=」processorClass」  
  3. Value=」org.springframework.web.struts.DelegatingRequestProcessor」/>  
  4. </controller>  

<controller> <set-property property=」processorClass」 Value=」org.springframework.web.struts.DelegatingRequestProcessor」/> </controller> 

 

b. 在Struts配置文件中的Action就不用再寫type屬性,在Spring配置文件中配置struts的action,配置規則以下:bean的name是struts1配置文件中action的path值。class的值爲action的全路徑。

注意:在spring中配置的action再也不使用id屬性,由於id中不容許特殊字符如「/」。

(2).方式2——全權委託方式:

a.在struts1的配置文件中,全部的action的type屬性值都寫爲:org.springframework.web.struts.Delegating.ActionProxy。

b. 在Spring配置文件中配置struts的action,配置規則以下:bean的name是struts1配置文件中action的path值。class的值爲action的全路徑。

注意:在spring中配置的action再也不使用id屬性,由於id中不容許特殊字符如「/」。

(3).方式3——struts的action繼承spring的ActionSupport方式:

a. struts中的全部action都繼承spring的ActionSupport類。

b. 在struts的配置文件中以下配置:

 

[xhtml] view plain copy print?

  1. <plug-in className=」org.springframework.web.struts.contextLoaderPlugIn」>  
  2.        <set-property property=」contextConfigLocation」 value=」spring配置文件路徑」/>  
  3. </plug-in>  

<plug-in className=」org.springframework.web.struts.contextLoaderPlugIn」> <set-property property=」contextConfigLocation」 value=」spring配置文件路徑」/> </plug-in> 

 

c. 在Struts配置文件中的Action就不用再寫type屬性,在Spring配置文件中配置struts的action,配置規則以下:bean的name是struts1配置文件中action的path值。class的值爲action的全路徑。

注意:在spring中配置的action再也不使用id屬性,由於id中不容許特殊字符如「/」。

相關文章
相關標籤/搜索