1. 程式人生 > >Spring中Aop的實現

Spring中Aop的實現

Spring中AOP的實現分為兩種:

一、Java配置實現

1、通過註解定義攔截規則

2、通過方法路徑定義攔截規則

二、XML配置實現

1、通過註解定義攔截規則

2、通過方法路徑定義攔截規則


 一、Java配置實現

(1)Java配置實現,定義一個註解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAction {
}

(2)定義Target,Target中有部分方法加有註解,凡是加有註解的方法都會被攔截下來,沒加註解的方法則不受影響:

@Component
public class MyCalcultor {   
     @MyAction    
     public int add(int a, int b) {   
         System.out.println("add。。。");  
          return a + b;    }   

     public String sayHello(String name) {   
         return "hello " + name + " !";   
     }
}

(3)定義切面,切面包含兩個部分:切點+增強(通知)分為五大類

*前置通知、通知在目標方法執行之前

*後置通知、通知在目標方法執行之後

*異常通知、通知在目標方法拋異常執行

*返回通知、通知在目標方法有返回值時執行

*環繞通知、包含了前面四種

@Component
@Aspect
public class LogAspect {   
     /**
       * @param point 引數是指連線點,從這個引數中,可以獲取方法名方法引數等資訊     
       * @Before註解表示這是一個前置通知,該通知會在目標方法執行之前執行    
       */  
    @Before("@annotation(MyAction)")    
    public void before(JoinPoint point) {        
    String name = point.getSignature().getName();        
    System.out.println(name + "方法開始執行了...");    
    }
}

(4)其他四種類型的通知

/** 
  * 這個類就是切面,該類中的內容包含兩大塊:切點+通知 
  * 
  * @Componet只是將該類註冊到Spring容器中 
  * @Aspect表示該類是一個切面  
  */@Component
  @Aspect
  public class LogAspect {    
      /**     
       * @param point 引數是指連線點,從這個引數中,可以獲取方法名方法引數等資訊     
       * @Before註解表示這是一個前置通知,該通知會在目標方法執行之前執行     
       */    
@Before("@annotation(MyAction)")    
public void before(JoinPoint point) {        
    String name = point.getSignature().getName();        
    System.out.println(name + "方法開始執行了...");    
}    

/**     
* 這是一個後置通知,後置通知在目標方法執行結束後執行     
* @param point     
*/    
@After("@annotation(MyAction)"){ 
    System.out.println(point.getSignature().getName() + "方法執行結束了...");    
}    

/**     
* 這是一個返回通知,可以獲取目標方法的返回值     
*     
* 方法中的引數名和註解中的引數名是對應的,引數值就是目標方法的返回值     
*     
* 需要注意返回值的型別,返回值的型別必須是引數的類或者子類     
*/    
@AfterReturning(value = "@annotation(MyAction)",returning = "result")    
public void returning(JoinPoint point,Object result) {
    System.out.println(point.getSignature().getName() + "方法的返回值是:" + result);    
}    

    /**     
    * 這是一個異常通知,該通知在方法執行丟擲異常時執行     
    *     
    * 如果目標方法沒有異常,則通知不會被觸發     
    */    
@AfterThrowing(value = "@annotation(MyAction)",throwing = "e")    
     public void throwing(JoinPoint point,Exception e) {                                     System.out.println(">>>>>"+e.getMessage());    
}    
    /**     
    * 環繞通知是上面四種通知的集大成者,因為這個通知中包含了上面四種通知的功能    
    *     
    * @param pjp 這個引數類似於Method物件     
    * @return     
    */    
@Around("@annotation(MyAction)")    
public Object around(ProceedingJoinPoint pjp) {        
    //pjp.proceed() 就類似於method.invoke()        
    try {            
        //寫在這個位置的,就是前置通知            
    Object proceed = pjp.proceed();            
        //寫在這個位置的,就是後置通知           
         return proceed;       
     }catch (Throwable throwable) {            
    //寫在這個位置的,就是異常通知            
        throwable.printStackTrace();        
    }        
        return null;    }
}

(5)可以通過如下方法簡化切點的定義:

   /**     
    * 可以單獨定義一個方法,專門用來定義切點,然後在其他方法中引用     
    */    
@Pointcut("@annotation(MyAction)")    
public void pointcut() {   

}

二、XML配置實現

(1)通過方法路徑定義攔截規則,實際上只是切點的定義方式變了,其他的還是一樣的。

 /**     
* 可以單獨定義一個方法,專門用來定義切點,然後在其他方法中引用     
*  第一個* 表示目標方法的返回值,可以是任意型別,*表示任意型別     
*  第二個*表示類中的任意方法     
*  兩個.表示方法的引數任意(可有可無,型別任意)     
*     
*  例如,想精確定位到add方法,步驟如下:     
*  execution(int com.itbaizhan.service.MyCalcultor.add(int,int))     
*/    
@Pointcut("execution(* com.itbaizhan.service.*.*(..))")    
public void pointcut() {  
  }

(2)使用表示式,可以較好的滿足最小侵入式原則。