一、介绍
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>
事务可以通过注解来进行声明,在以后的章节中会详细讲事务。