spring知识点分析之aop

一、介绍

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. 名称匹配
  2. 正则表达式匹配

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的注解:

  1. @Before – 方法执行前运行
  2. @After – 运行在方法返回结果后
  3. @AfterReturning – 运行在方法返回一个结果后,在拦截器返回结果。
  4. @AfterThrowing – 运行方法在抛出异常后,
  5. @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>

事务可以通过注解来进行声明,在以后的章节中会详细讲事务。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章