一、介紹
Spring對面向切面編程提供了強有力的支持,通過它讓我們將業務邏輯從應用服務(事務管理)中分離出來,實現
了高內聚開發,應用對象只關注業務邏輯,不再負責其他系統問題(如日誌、事務、權限控制),Spring支持用戶自定義切面。
面向切面編程完善spring的依賴注入,面向切面編程在spring中主要表現在兩個方面:
1.面向切面編程提供聲明式事務管理
2.spring支持用戶自定義的切面
面向切面編程是對面向對象編程的補充,面向對象編程將程序分解成各個層次的對象,面向切面編程將程序運行
過程分解成各個切面。aop從程序運行角度考慮程序的結構,提取業務處理過程的切面,oop是靜態的抽象,aop
是動態的抽象,是對應用執行過程中的步驟進行抽象,從而獲得步驟之間的邏輯劃分。通俗地講,它相當於一個
攔截器,攔截一些過程,例如,當一個方法執行,spring aop可以劫持一個執行的方法,在方法執行之前或之後
添加額外的功能。
1.特點
優點:①各個步驟之間的良好隔離性
②源代碼無關性
③把次要問題代碼放在一個統一的地方,而不是在基本業務邏輯中
AOP核心概念
1、橫切關注點
對哪些方法進行攔截,攔截後怎麼處理,這些關注點稱之爲橫切關注點
2、切面(aspect)
類是對物體特徵的抽象,切面就是對橫切關注點的抽象
3、連接點(joinpoint)
被攔截到的點,因爲Spring只支持方法類型的連接點,所以在Spring中連接點指的就是被攔截到的方法,實際上連接點還可以是字段或者構造器
4、切入點(pointcut)
對連接點進行攔截的定義
5、通知(advice)
所謂通知指的就是指攔截到連接點之後要執行的代碼,通知分爲前置、後置、異常、最終、環繞通知五類
6、目標對象
代理的目標對象
7、織入(weave)
將切面應用到目標對象並導致代理對象創建的過程
8、引入(introduction)
在不修改代碼的前提下,引入可以在運行期爲類動態地添加一些方法或字段
二、通知
一個類的整個方法被自動攔截。
1.通知類型
spring aop中,有四種類型通知的支持:
①在通知之前:該方法執行運行前運行
②通知返回之後:運行後,該方法返回一個結果
③通知拋出之後:運行方法拋出異常後
④環繞通知:環繞方法執行運行,結合以上三個通知
2 實例
①在通知之前:
1.創建 java project
2.創建接口User.java
package com.spring;
public interface User {
void printName();
void printAge();
void printThrowException();
}
3.創建實現類IUser.java,實現User接口
package com.spring;
public class User implements IUser {
private String name;
private Integer age;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public void printName() {
System.out.println("我的名字是:"+name);
}
@Override
public void printAge() {
System.out.println("我的今年的年齡是:"+age);
}
public void printThrowException() {
throw new IllegalArgumentException();
}
}
4.創建一個實現 MethodBeforeAdvice 接口的類 UserBeforeMethod
package com.spring;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
* 之前通知
* 他會在方法執行之前執行
*
*
*/
public class UserBeforeMethod implements MethodBeforeAdvice{
@Override
public void before(Method arg0, Object[] arg1, Object target) throws Throwable {
System.out.println("UserbeforeMethod:before method //執行業務邏輯方法前要執行的代碼功能");
}
}
5.applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 目標類,使用動態代理實現aop時,目標類必須要實現接口 -->
<bean name="user" class="com.spring.User">
<property name="name" value="石義賓"/>
<property name="age" value="26"/>
</bean>
<!-- 新的代理對象,在業務邏輯方法之前要執行的功能 -->
<bean name="userProxyBean" class="com.spring.UserBeforeMethod"></bean>
<!-- ProxyFactoryBean:產生代理類的工廠 ,結合代理類對象和目標對象生成新的代理對象-->
<bean name ="ProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- interceptorNames屬性:指明要在代理的目標類中添加的功能,即advice -->
<property name="interceptorNames">
<list>
<value>userProxyBean</value>
</list>
</property>
<!-- target屬性:指明要代理的目標類 ,這個目標類實現了上面proxyInterfaces屬性指定的接口 -->
<property name="target" >
<ref bean="user"/>
</property>
<!-- proxyInterfaces屬性:指明要代理的接口,可以不指定 -->
<!-- <property name="proxyInterfaces"></property>-->
<!-- proxyTargetClass屬性:,如果這個屬性被設定爲“true”,說明 ProxyFactoryBean要代理的不是接口類,而是要使用CGLIB方式來進行代理 -->
<!-- <property name="proxyTargetClass"></property> -->
</bean>
</beans>
6.測試類
package com.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//User user = applicationContext.getBean(User.class);
//必須轉成接口類型
//得到的是新的ProxyFactoryBean bean,而不是原來的user bean
//它將運行 HijackBeforeMethod 的 before() 方法,在每個 CustomerService 的方法之前執行。
IUser user = (IUser)applicationContext.getBean("ProxyFactoryBean");
System.out.println("*********name開始***************");
user.printName();
System.out.println("*********name結束***************");
System.out.println("*********age開始****************");
user.printAge();
System.out.println("*********age結束****************");
}
}
②返回後通知
1-3如上
4.創建一個實現 AfterReturningAdvice接口的類 UserAfterMethod
package com.spring;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
/**
* 該方法返回一個結果之後它將執行
*
*/
public class UserAfterMethod implements AfterReturningAdvice{
@Override
public void afterReturning(Object var1, Method var2, Object[] var3, Object var4) throws Throwable {
System.out.println("UserAfterMethod:after method //執行業務邏輯方法返回結果之後要執行的代碼功能");
}
}
5.與上類似,只需要將applicationContext.xml中的bean userProxyBean對應的類改成UserAfterMethod即可
6.測試 ---如上
③通知拋出之後
1-3如上
4.創建一個實現 ThrowsAdvice接口的類 UserThrowExepection
package com.spring;
import org.springframework.aop.ThrowsAdvice;
/**
*
* 它將在執行方法拋出一個異常後
*
*
*/
public class UserThrowExpection implements ThrowsAdvice{
//創建一個afterThrowing方法攔截拋出:IllegalArgumentException異常。
public void afterThrowing(IllegalArgumentException e)throws Throwable {
//執行業務邏輯方法之後,會拋出一個異常,該方法會捕獲異常並執行
System.out.println("UserThrowExpection:Throw exception");
}
}
5.與上類似,只需要將applicationContext.xml中的bean userProxyBean對應的類改成UserThrowExepection即可
6.測試
package com.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//User user = applicationContext.getBean(User.class);
//必須轉成接口類型
IUser user = (IUser)applicationContext.getBean("ProxyFactoryBean");
System.out.println("*********name開始***************");
user.printName();
System.out.println("*********name結束***************");
System.out.println("*********age開始****************");
user.printAge();
System.out.println("*********age結束****************");
try {
//拋出一個異常,就會被UserThrowExpection捕獲
user.printThrowException();
} catch(Exception e) {
}
}
}
④環繞通知
1-3如上
4.創建一個實現了MethodInterceptor接口的類UserAroundMethod
package com.spring;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
*
* 它結合了其它的三個通知,在方法執行過程中執行。這種通知也是常用的
*/
public class UserAroundMethod implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("Method name : "
+ methodInvocation.getMethod().getName());
System.out.println("Method arguments : "
+ Arrays.toString(methodInvocation.getArguments()));
// same with MethodBeforeAdvice
System.out.println("UserAroundMethod : Before method!");
try {
//必須調用“methodInvocation.proceed(); 繼續在原來的方法執行,否則原來的方法將不會執行。
//相當於執行業務邏輯方法
Object result = methodInvocation.proceed();
System.out.println("UserAroundMethod :after method!");
return result;
}catch(IllegalArgumentException e) {
System.out.println("UserAroundMethod : Throw exception!");
throw e;
}
}
}
5.與上類似,只需要將applicationContext.xml中的bean userProxyBean對應的類改成UserAroundMethod即可
6.測試
Test如③
三、切入點
在二的通知中都是一個類的整個方法都被攔截下來,但是在大多數情況下可能只需要一種方式來攔截一個或者兩個方法,
這就是爲什麼要引入切入點,它允許通過它的方法名來攔截方法。另外一個切入點必須具有advisor相關聯。
spring aop中有三個專業術語:
- Advice – 指示之前或方法執行後採取的行動。
- Yiibaicut – 指明哪些方法應該攔截,通過方法的名稱或正則表達式模式。
- Advisor – 分組"通知"和”切入點“成爲一個單元,並把它傳遞到代理工廠對象。
可以通過以下兩種方式匹配方法:
- 名稱匹配
- 正則表達式匹配
1.實例
(1)名稱匹配
1-3如上
4.不需要創建相關的通知類。Spring提供了PintcutAdvisor類來保存工作聲明advisor和切入點到不同的bean,
可以使 用 NameMatchMethodPointcutAdvisor 兩者結合成一個 bean。直接在配置文件中配置。
5.applicationContext.xml
5.1 通過“切入點”和“advisor”攔截printName()方法。創建NameMatchMethodPointcut切入點bean,並提出
要在“mappedName”屬性值來攔截方法名。
<bean id="userPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedName" value="printName"></property>
</bean>
5.2 創建 DefaultPointcutAdvisor 通知 bean,通知和切入點相關聯。
<bean id="userAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="userPointcut"></property>
<property name="advice" ref="userAroundMethod"></property>
</bean>
5.3 更換代理“interceptorNames”到“customerAdvisor”(它是“userAroundMethod”)。
<bean id="customerserviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="customerservice"></property>
<property name="interceptorNames">
<list>
<value>userAdvisor</value>
</list>
</property>
</bean>
5.4 完整的applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 目標類,使用動態代理實現aop時,目標類必須要實現接口 -->
<bean name="user" class="com.spring.User">
<property name="name" value="石義賓"/>
<property name="age" value="25"/>
</bean>
<!-- 通知 -->
<bean id="userAroundMethod" class="com.spring.UserAroundMethod"></bean>
<!-- 1:通過“切入點”和“advisor”攔截printName()方法。創建NameMatchMethodYiibaicut切入點bean,並提出要在“mappedName”屬性值來攔截方法名。 -->
<!-- 代替之前的userProxyBean-->
<bean id="userPointcut"
class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedName" value="printName" />
</bean>
<!-- 2: 創建 DefaultPointcutAdvisor 通知 bean,通知和切入點相關聯-->
<bean id="userAdvisor"
class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="userPointcut" />
<property name="advice" ref="userAroundMethod" />
</bean>
<!-- ProxyFactoryBean:產生代理類的工廠 ,結合代理類對象和目標對象生成新的代理對象-->
<bean name ="ProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- interceptorNames屬性:指明要在代理的目標類中添加的功能,即advice -->
<property name="interceptorNames">
<list>
<!--3: 更換代理 ,用customerAdvisor(結合切入點)代替之前的userProxyBean(單純通知)-->
<value>userAdvisor</value>
</list>
</property>
<!-- target屬性:指明要代理的目標類 ,這個目標類實現了上面proxyInterfaces屬性指定的接口 -->
<property name="target" >
<ref bean="user"/>
</property>
<!-- proxyInterfaces屬性:指明要代理的接口,可以不指定 -->
<!-- <property name="proxyInterfaces"></property>-->
<!-- proxyTargetClass屬性:,如果這個屬性被設定爲“true”,說明 ProxyFactoryBean要代理的不是接口類,而是要使用CGLIB方式來進行代理 -->
<!-- <property name="proxyTargetClass"></property> -->
</bean>
</beans>
5.5 測試
測試類不變,從結果可以,只攔截了printName()方法。
(2) 正則表達式
可以通過使用正則表達式匹配切入點方法的名稱 – RegexpMethodPointcutAdvisor
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 目標類,使用動態代理實現aop時,目標類必須要實現接口 -->
<bean name="user" class="com.spring.User">
<property name="name" value="石義賓"/>
<property name="age" value="25"/>
</bean>
<!-- 通知 -->
<bean id="userAroundMethod" class="com.spring.UserAroundMethod"></bean>
<!-- 2: 創建 DefaultPointcutAdvisor 通知 bean,通知和切入點相關聯-->
<!--它攔截方法名稱中有“URL”的方法。在實踐中,可以用它來管理DAO層,聲明“.*DAO.*” 攔截所有的DAO類來支持事務-->
<bean id="userAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!--不需要直接引入需要被代理的bean-->
<property name="patterns">
<list>
<value>.*URL.*</value>
</list>
</property>
<property name="advice" ref="userAroundMethod" />
</bean>
<!-- ProxyFactoryBean:產生代理類的工廠 ,結合代理類對象和目標對象生成新的代理對象-->
<bean name ="ProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- interceptorNames屬性:指明要在代理的目標類中添加的功能,即advice -->
<property name="interceptorNames">
<list>
<!--3: 更換代理 ,用customerAdvisor(結合切入點)代替之前的userProxyBean(單純通知)-->
<value>userAdvisor</value>
</list>
</property>
<!-- target屬性:指明要代理的目標類 ,這個目標類實現了上面proxyInterfaces屬性指定的接口 -->
<property name="target" >
<ref bean="user"/>
</property>
<!-- proxyInterfaces屬性:指明要代理的接口,可以不指定 -->
<!-- <property name="proxyInterfaces"></property>-->
<!-- proxyTargetClass屬性:,如果這個屬性被設定爲“true”,說明 ProxyFactoryBean要代理的不是接口類,而是要使用CGLIB方式來進行代理 -->
<!-- <property name="proxyTargetClass"></property> -->
</bean>
</beans>
在IUser接口中加上一個printURL()方法,並在User中實現重寫,然後在測試類中調用該方法。其結果如下:
現在,它攔截方法名稱中有“URL”的方法,在實踐中,可以用它來管理DAO層,聲明“.*DAO.*” 攔截所有的
DAO類來支持事務。
三、自動代理創建者
在一和二中,必須手動創建一個代理bean(ProxyFactoryBean),對每個bean需要aop支持。這種方法並不有效,
因爲這種手動方式意味着,如果有一個客戶模塊,所有的dao類實現sql日誌支持(提醒)的aop功能,那麼就要針
每個dao創建對應的代理工廠bean,這就會導致bean配置文件會氾濫代理類。爲此spring提供了兩個自動代理創
建者來自動創建代理bean。
1.BeanNameAutoProxyCreator
在此之前需要使用代理名稱來獲得bean:
IUser user = (IUser)applicationContext.getBean("ProxyFactoryBean");
在自動代理機制,只需要創建一個BeanNameAutoProxyCreator幷包含所有你的bean(通過bean的名字,或正則表達式名)和“advisor” 作爲一個單位。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 目標類,使用動態代理實現aop時,目標類必須要實現接口 -->
<bean name="userDao" class="com.spring.User">
<property name="name" value="石義賓"/>
<property name="age" value="25"/>
</bean>
<!-- 通知 -->
<bean id="userAroundMethod" class="com.spring.UserAroundMethod"></bean>
<!-- 2: 創建 DefaultPointcutAdvisor 通知 bean,通知和切入點相關聯-->
<!--它攔截方法名稱中有“URL”的方法。在實踐中,可以用它來管理DAO層,聲明“.*DAO.*” 攔截所有的DAO類來支持事務-->
<bean id="userAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!--不需要直接引入需要被代理的bean-->
<property name="patterns">
<list>
<value>.*URL.*</value>
</list>
</property>
<property name="advice" ref="userAroundMethod" />
</bean>
<!--代替之前的ProxyFactoryBean-->
<bean
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<!--符合該正則的bean-->
<value>*Dao</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>customerAdvisor</value>
</list>
</property>
</bean>
</beans>
現在,可以通過“userDao”的原始名稱獲取bean, 如果知道這個bean已經代理。
IUser user = (IUser)appContext.getBean("userDao");
2.DefaultAdvisorAutoProxyCreator
DefaultAdvisorAutoProxyCreator是非常強大的,如果有bean相關聯,spring會自動創建一個代理。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 目標類,使用動態代理實現aop時,目標類必須要實現接口 -->
<bean name="userDao" class="com.spring.User">
<property name="name" value="石義賓"/>
<property name="age" value="25"/>
</bean>
<!-- 通知 -->
<bean id="userAroundMethod" class="com.spring.UserAroundMethod"></bean>
<!-- 2: 創建 DefaultPointcutAdvisor 通知 bean,通知和切入點相關聯-->
<!--它攔截方法名稱中有“URL”的方法。在實踐中,可以用它來管理DAO層,聲明“.*DAO.*” 攔截所有的DAO類來支持事務-->
<bean id="userAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!--不需要直接引入需要被代理的bean-->
<property name="patterns">
<list>
<value>.*URL.*</value>
</list>
</property>
<property name="advice" ref="userAroundMethod" />
</bean>
<!--不需要指定任何,自動根據bean去引入-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/></beans>
五、AspectJ
AspectJ註解集成到spring aop中,可以很輕鬆實現方法的攔截。
常見的AspectJ的註解:
- @Before – 方法執行前運行
- @After – 運行在方法返回結果後
- @AfterReturning – 運行在方法返回一個結果後,在攔截器返回結果。
- @AfterThrowing – 運行方法在拋出異常後,
- @Around – 圍繞方法執行運行,結合以上這三個通知。
六、spring aop在ssm(spring+springmvc+mybatis)中的配置使用
這裏以事務爲例。
我們只需要在spring-mybatis.xml文件中配置如下:
1.導入aop的引用:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
2.配置spring的事務管理器
<!-- 事務核心管理器,封裝了所有事務操作. 依賴於連接池 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
3.配置aop全局事務管理
<!--aop全局事務管理(下面基於dao層)-->
<aop:config>
<aop:pointcut id="allDaoMethods"
expression="execution(* com..dao..*(..))"/>
<aop:advisor advice-ref="defaultTransactionAdvice"
pointcut-ref="allDaoMethods"/>
</aop:config>
4.配置事務管理的通知(具體指定aop攔截到的哪些方法需要創建/使用事務)
<tx:advice id="defaultTransactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--<tx:method name="*" isolation="DEFAULT"-->
<!--propagation="REQUIRED" no-rollback-for="java.lang.RuntimeException" timeout="100"/>-->
<!--<tx:method name="*" read-only="true"/>-->
<!-- 以方法爲單位,指定方法應用什麼事務屬性 isolation:隔離級別 propagation:傳播行爲 read-only:是否只讀 -->
<!--PROPAGATION_REQUIRED:支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。-->
<!--PROPAGATION_SUPPORTS:支持當前事務,如果當前沒有事務,就以非事務方式執行。-->
<!--PROPAGATION_MANDATORY:支持當前事務,如果當前沒有事務,就拋出異常。-->
<!--PROPAGATION_REQUIRES_NEW:新建事務,如果當前存在事務,把當前事務掛起。-->
<!--PROPAGATION_NOT_SUPPORTED:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。-->
<!--PROPAGATION_NEVER:以非事務方式執行,如果當前存在事務,則拋出異常。-->
<!--PROPAGATION_NESTED:支持當前事務,如果當前事務存在,則執行一個嵌套事務,如果當前沒有事務,就新建一個事務。-->
<tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="Borrow*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="create*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="merge*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="del*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="remove*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="put*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="use*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
七、spring aop在ssh(struts2+spring+hibernate)中的配置使用
1.如上
2.配置spring的事務管理器
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
3.配置bean事務有兩種方式
第一種方式:使用TransactionProxyFactoryBean創建事務代理
<!-- 事務 -->
<bean id="baseServiceProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<!--使用事務的bean-->
<ref local="baseService" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="search*">readOnly</prop>
<prop key="list*">readOnly</prop>
</props>
</property>
</bean>
第二種方式:
先配置事務傳播性
<!-- 配置事務的傳播特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager" >
<tx:attributes>
<!-- 在開發的時候可以這樣定義,但部署的時候一定要詳細定義 -->
<tx:method name="*" propagation="REQUIRED"/>
<!--
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>
-->
</tx:attributes>
</tx:advice>
<!-- 配置哪些類哪些方法使用事務 -->
<aop:config>
<aop:pointcut id="txAdvicePointcut" expression="execution(* com.nuist.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txAdvicePointcut"/>
</aop:config>
事務可以通過註解來進行聲明,在以後的章節中會詳細講事務。