spring2.0基于XML Schema的AOP实现以及AOP事务

来源:互联网 发布:美库尔数据库 编辑:程序博客网 时间:2024/05/16 06:47

1. Before Advice和After Advice

import org.aspectj.lang.JoinPoint;

public class LogAdvice {

 //基于XML Schema实现Before Advice时,Advice类不用实现org.springframework.aop.MethodBeforeAdvice接口(spring2.0才提供)
 //before方法是在目标对象上的方法被执行前要执行的方法,before方法中的JoinPoint参数是可选项,可以根据需要决定是否需要JoinPoint参数,
 //通过JoinPoint对象可以获得目标对象(getTarget())、目标方法上的参数(getArgs())等信息,然后在XML中为目标对象指定代理
 public void before(JoinPoint joinPoint) { 
  //System.out.println(" method before: " + joinPoint.getTarget().getClass().getName() +"."+ joinPoint.getSignature().getName() + " START");
  for(Object o :joinPoint.getArgs()){
   if (o == null){
    //System.out.println("param  : " + o);
   } else {
    //System.out.println("param  : " + o.toString());
   }
  }
    }
 
 //基于XML Sechma实现After Returning Advice时,不需要org.springframework.aop.AfterReturningAdvice接口(spring2.0才提供)
 public void after(JoinPoint joinPoint) { 
  //System.out.println(" method after : " + joinPoint.getTarget().getClass().getName() +"."+ joinPoint.getSignature().getName() + " END");
 } 
}

2. Around Advice

import org.aspectj.lang.ProceedingJoinPoint;

public class LogAroundAdvice {

 //Spring2.0中,Around Advice不用实现org.aoplliance.intercept.MethodInterceptor接口,但Advice方法必须返回对象,并且必须定义一个ProceedingJoinPoint参数
  public Object invoke(ProceedingJoinPoint joinPoint) { 
  
   System.out.println(" LogAroundAdvice before    " + joinPoint.getSignature().getName()); 
     Object retVal = null;
  try {
   retVal = joinPoint.proceed();
  } catch (Throwable e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } 
  System.out.println(" LogAroundAdvice after    " + joinPoint.getSignature().getName()); 
  return retVal; 
  }
 
}

3. Throw Advice

import org.aspectj.lang.JoinPoint;

public class LogThrowingAdvice {
 
 //Spring2.0中,Throw Advice不用实现org.springframework.aop.ThrowsAdvice接口,但Advice方法必须定义Throwable(或其子类)参数
 //<aop:after-throwing></aop:after-throwing>中必须定义throwing属性,指定方法中的throwable参数.Spring将根据异常类型决定是否调用afterThrowing方法.
 public void afterThrowing (JoinPoint joinPoint, Throwable throwable) { 
  System.out.println("  LogThrowingAdvice : " + joinPoint.getSignature().getName()); 
 } 
}

4.

 <!--编写业务逻辑方法
  编写业务逻辑方法时,最好将异常一直向上抛出,在表示层(struts)处理
  关于事务边界的设置,通常设置到业务层,不要添加到Dao上
  --> 
    <!-- =================================================================== -->
    <!-- AOP: Configuration and Aspects                                      -->
    <!-- =================================================================== -->
    <!-- AOP配置,使用基于XML Sechma声明AOP的方式,需要在XML中加入aop的名称空间 --> 
    <aop:config>
        <!-- 声明事务切入点(配置哪些类的哪些方法参与事务),可以有多个 -->
        <aop:pointcut id="managerTx"  expression="execution(* *..service.*Manager.*(..))"   /> 
        <!-- 通知器(把事务通知绑定到切入点),可以有多个 --> 
        <aop:advisor pointcut-ref="managerTx" advice-ref="txAdvice" order="0" />
        <!--
  Spring2.0中,Pointcut的定义包括两个部分:Pointcut表示式(expression)和Pointcut签名(signature).
  先看看execution表示式的格式:execution(modifier-pattern?ret-type-pattern?declaring-type-pattern?name-pattern?param-pattern?throws-pattern?)
                      括号中各个pattern分别表示修饰符匹配(modifier-pattern)、返回值匹配(ret-type-pattern)、类路径匹配(declaring-type-pattern)、方法名匹配(name-pattern)、
                      参数匹配((param-pattern))、异常类型匹配(throws-pattern),其中后面跟着“?”的是可选项.在各个pattern中可以使用“*”来表示匹配所有.在(param-pattern)中,可以指定具体的参数类型,
                      多个参数间用“,”隔开,各个也可以用“*”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(*,String)表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(..)表示零个或多个任意参数.             
   现在来看看几个例子:                
  1)execution(* *(..))表示匹配所有方法
  2)execution(public * com. savage.service.UserService.*(..))表示匹配com.savage.server.UserService中所有的公有方法
  3)execution(* com.savage.server..*.*(..))表示匹配com.savage.server包及其子包下的所有方法
  除了execution表示式外,还有within、this、target、args等Pointcut表示式。一个Pointcut定义由Pointcut表示式和Pointcut签名组成,Pointcut定义时,还可以使用and、or、not运算.                                         
        --> 
         <aop:aspect id="logAspect" ref="logAdvice" order="1">
   <aop:pointcut id="logPointcut" expression="execution(* *..service.*Manager.*(..)) or execution(* *..dao.*Dao.*(..))"/>
   <!-- 前置通知:对于一个通知来说,切入点和对应的通知方法是必须的.也就是说,method属性是必须的,必须给通知指定一个对应方法;pointcut属性和pointcut-ref必须有一个被指定,确定该通知切入点 --> 
   <aop:before pointcut-ref="logPointcut" method="before"/>
   <!-- 后置通知--> 
   <aop:after pointcut-ref="logPointcut" method="after"/>
   </aop:aspect>
        <aop:aspect id="logAround" ref="logAroundAdvice" order="2"> 
           <!-- 环绕通知:所有通知中功能最强大的通知--> 
              <aop:around pointcut="execution(* *..service.*Manager.*(..)) or execution(* *..dao.*Dao.*(..))" method="invoke"/> 
        </aop:aspect>
        <aop:aspect id="logThrowing" ref="logThrowingAdvice" order="3"> 
          <!-- 异常通知:有一个类似于throwing属性来指定该通知匹配的异常类型 --> 
          <aop:after-throwing throwing="throwable" method="afterThrowing" pointcut="execution(* *..service.*Manager.*(..))"/>
        </aop:aspect>
        <!-- 返回后通知:用于将链接点的返回值传给通知方法,比aop:after多了个returning属性 --> 
    </aop:config>

 

 

    <bean id="logAdvice" class="cn.xue.app.advice.LogAdvice"/>
    <bean id="logAroundAdvice" class="cn.xue.app.advice.LogAroundAdvice"/>
    <bean id="logThrowingAdvice" class="cn.xue.app.advice.LogThrowingAdvice"/>
   
    <!-- 定义事务通知 --> 
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
     <!--配置事务的传播特性 --> 
     <!--事务的传播行为
  REQUIRED: 业务方法需要在一个事务中运行,如果方法运行时,已经存在一个事务中,那么加入到该事务,否则自己创建一个新事务。
  SUPPORTS: 如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分,如果业务方法在事务外被调用,则方法在没有事务的环境下执行。
  MANDATORY: 业务方法只能在一个已经存在的事务中进行,业务方法不能发起自己的事务,如果方法在没有事务的环境中调用,那么容器会抛出例外。
  REQUIRESNEW: 不管是否存在事务,业务方法总为自己发起一个新事务;如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法调用结束,新事务才结束,原先的事务再恢复执行。
  NOT_SUPPORTED: 声明方法不需要事务,如果方法没有关联到事务,容器不会为它开启事务,如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行。
  NEVER: 业务方法绝对不能再事务范围内执行,如果方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,方法才能够正常执行。
  NESTED:  如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动事务,则按照REQUIRED属性执行,它使用了一个单独的事务,这个事务有多个可以回滚的保存点,
                          内部事务的回滚不会对外部事务产生影响。它只对DataSourceTransactionManager事务管理器有效。
     -->
     <!--事务的隔离级别,注:Spring中事务的隔离级别是由数据库实现的
  ISOLATION_DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应
  ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读
  ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
  ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
  ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
  脏读:  一个事务读取到另一个事务未提交的更新数据。
  不可重复读: 在同一事务中,多次读取同一数据返回的结果有所不同,即后续读取可以读取到另一事务已提交的更新数据;相反,"可重复读"是指在同一事务中多次读取数据时,能够保证所读取的数据是一样,即后续读取不能读到另一事务已提交的数据。
  幻读:  一个事务读取到另一事务已提交的insert数据。
      -->
        <tx:attributes>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

原创粉丝点击