Spring AOP增強

1.使用AOP前的準備工作

1.1 引入相關的jar包

在這裏插入圖片描述

1.2 在spring配置文件的beans添加aop規範

xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="     
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop.xsd"

2. AOP增強使用方式

2.0 執行順序

  • Before前置增強→原方法執行→[異常增強]→After最終增強→AfterReturning後置返回增強(有異常不會執行AfterReturning)

2.1 增強類型

  • 2.1.1前置增強:在被增強的方法執行前攔截
package com.aop;
 
import java.lang.reflect.Method;
import java.util.Arrays;
import org.springframework.aop.MethodBeforeAdvice;
 
//實現MethodBeforeAdvice接口表示該類爲前置增強類
public class BeforeAdvice implements MethodBeforeAdvice {
    /*
     *參數method表示被增強的方法的方法對象
     *參數args表示被增強的方法的參數數組
     *參數target表示被增強的方法所屬的類的對象
     */
    public void before(Method method, Object[] args, Object target)
            throws Throwable {
        System.out.println("調用"+target+"的"+method.getName()+"方法,方法入參:"+Arrays.toString(args));
    }
}
  • 2.1.2 後置增強 :在被增強的方法執行後攔截
    • 最終增強與後置增強要區分好
package com.aop;
 
import java.lang.reflect.Method;
import java.util.Arrays;
import org.springframework.aop.AfterReturningAdvice;
 
//實現AfterReturningAdvice接口表示該類爲後置增強類
public class AfterAdvice implements AfterReturningAdvice {
    /*
     *參數result表示被增強的方法的返回值
     *參數method表示被增強的方法的方法對象
     *參數args表示被增強的方法的參數數組
     *參數target表示被增強的方法所屬的類的對象
     */
    public void afterReturning(Object result, Method method, Object[] args,
            Object target) throws Throwable {
        System.out.println("調用"+target+"的"+method.getName()+"方法,方法入參:"+Arrays.toString(args)+",方法返回值是"+result);
    }
}
  • 2.1.3 異常拋出增強:在被增強的方法拋出異常後攔截
package com.aop;
 
import java.lang.reflect.Method;
 
import org.springframework.aop.ThrowsAdvice;
 
//實現ThrowsAdvice接口表示該類爲異常拋出增強類
public class ExceptionAdvice implements ThrowsAdvice{
        /*
         *參數method表示被增強的方法的方法對象
         *參數args表示被增強的方法的參數數組
         *參數target表示被增強的方法所屬的類的對象
         *參數e表示異常,類型可以是任意的運行時異常
         */
     
        /*
         * 1、實現ThrowsAdvice接口跟其他增強接口不同,它不會提供必須實現的方法
         * 2、方法命名規則: void afterThrowing([Method method, Object[] args, Object target,] Throwable e)
         *         中括號包含的參數要麼全要,要麼全都不要,異常參數是必須的,方法名必須是afterThrowing
         * 3、異常拋出增強類不能catch異常,執行完afterThrowing方法後程序依然會終止
         * 
         */
        public void afterThrowing(Method method, Object[] args, Object target,RuntimeException e) {
            System.out.println("出現錯誤:"+e.getMessage());
        }
}
  • 2.1.4 環繞增強:在被增強的方法執行前和執行後都進行攔截
package com.aop;
 
import java.lang.reflect.Method;
import java.util.Arrays;
 
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
 
//實現MethodInterceptor接口表示該類爲環繞增強類
public class AroundAdvice implements MethodInterceptor{
 
    //參數ai包含了被代理的對象,方法,參數等
    public Object invoke(MethodInvocation ai) throws Throwable {
        Object target=ai.getThis();                //獲取被代理的對象
        Method method=ai.getMethod();          //獲取被代理的方法
        Object[] args=ai.getArguments();       //獲取方法參數
        System.out.println("調用"+target+"的"+method.getName()+"方法,方法入參:"+Arrays.toString(args));
        try {
            //proceed()方法調用目標對象的相應方法
            Object result=ai.proceed();
            System.out.println("調用"+target+"的"+method.getName()+"方法,方法入參:"+Arrays.toString(args)+",方法返回值是"+result);
            return result;
        } catch (Exception e) {
            //拋出異常
            System.out.println(method+ "方法出現異常:"+e);
            throw e;
        }
    }
 
}

  • 2.1.5 最終增強:即使拋出異常也會進行攔截,跟finally差不多
public class FinalAdvice implements AfterAdvice {}

2.2 切入點表達式

  • 格式
    訪問修飾符? 方法返回值類型 [類的全局路徑.]? 方法名(參數列表)

  • 分析

    • 主要分成4部分:訪問修飾符(可有可無)、方法返回值類型、方法、參數列表
    • 方法是由類的全局路徑.方法名組成,類的全局路徑可省略,表示任意包下的所有類的指定方法
    • 訪問修飾符丶方法返回值類型丶方法名使用*表示任意的返回值類型丶任意訪問修飾符丶任意方法
    • 方法使用包名.*.*表示指定包名下所有類的所有方法,第一個.*是所有類,第二個.*是所有方法
    • 方法使用包名..*.*表示指定包名及其子包下的所有類的所有方法,第一個.表示其所有子包,第二個.*是所有類,第三個.*次表示所有方法
    • 方法的字符.*表示指定包的指定類的所有方法,字符*表示以指定字符開頭的方法
    • 參數使用..表示任意類型任意個數任意順序的參數列表
  • 例子

//公有的任意返回值類型的帶一個User類型參數的save方法
* public * save(com.entity.User)    

//所有的公有方法
* public * *(..)                    

//表示com.biz.impl包下的所有類的所有方法
* * com.biz.impl.*.*(..)            

//表示com.biz.impl包及其子包下的所有類的所有方法
* * com.biz.impl..*.*(..)      

//表示所有以Impl開頭的方法     
* * Impl*(..)                       

2.3 spring配置文件添加AOP配置

        <!-- 配置AOP -->
    <aop:config>
        <!-- aop:pointcut標籤配置切入點,id屬性爲切入點的名字,expression屬性爲切入點指示符 -->
        <!-- 這裏切入點爲 com.biz.impl包及其子包下的所有類的所有方法-->
        <aop:pointcut id="pointcut" expression="execution(* com.biz.impl..*.*(..))" />
        <!-- aop:advisor標籤配置增強處理器,增加類實現了接口纔可以用這個標籤,advice-ref屬性爲增強處理器的實例id,pointcut-ref屬性爲切入點id-->
        <aop:advisor advice-ref="beforeAdvice" pointcut-ref="pointcut" />
        <aop:advisor advice-ref="afterAdvice" pointcut-ref="pointcut" />
        <aop:advisor advice-ref="exceptionAdvice" pointcut-ref="pointcut" />
        <aop:advisor advice-ref="aroundAdvice" pointcut-ref="pointcut" />

		<!-- aop:aspect標籤用於沒有實現接口的普通增強類 -->
		<!-- ref爲普通增強類的實例id -->
		<aop:aspect ref="myAspect">
			<!-- aop:before表示前置增強 -->
			<!-- method表示普通增強類中哪個方法作爲前置增強方法  -->
			<!-- pointcut-ref表示切入點id -->
			<aop:before method="before" pointcut-ref="pointcut"/>
			
			<!-- 這裏還可以配置其他類型的增強 -->
		</aop:aspect>
	
    </aop:config>

3. AOP註解

3.1 增強類

package com.advice;
 
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
 
//@Aspect標誌一個類是增強類
@Aspect
public class LogAdvice {
	//定義切入點方法
   @Pointcut(value="execution(* com.biz.impl..*.del(..))")
   private void pointcut1(){}
     
    //Before(pointcut)表示前置增強
   //pointcut的值可以引用切入點方法
    @Before("pointcut1()")
    public void before(JoinPoint jp){   
        //JoinPoint可以獲取被增強的方法信息
        System.out.println("【前置增強】開始執行方法"+jp.getSignature());
    }
     
    //AfterReturning(pointcut,returning)表示後置增強,出現異常不會進入本方法
    //returning="returnValue"表示把被增強的返回值注入到參數returnValue中
    @AfterReturning(pointcut="pointcut1()",returning="result")
    public void afterReturning(JoinPoint jp,Object result){
    	 System.out.println("【後置增強】"+jp.getSignature().getName()+"方法執行完畢,返回值是"+result);       
    }
     
    //AfterThrowing(pointcut,throwing)表示異常增強,出現異常時會進入本方法,但是不能捕捉異常
    @AfterThrowing(pointcut="pointcut1()",throwing="e")
    public void afterThrowing(JoinPoint jp,RuntimeException e){
    	 System.out.println(jp.getSignature().getName()+"方法發生異常:"+e.getMessage());
    }
     
    //After(pointcut)表示最終增強,相當於finally塊,即使出現異常也會進入本方法
    @After("pointcut1()")
    public void after(JoinPoint jp){
    	 System.out.println("【最終增強】"+jp.getSignature().getName());
         
    }
     
    //Around(pointcut)表示環繞增強,可以通過代碼編寫實現上面幾種增強的功能
    @Around("execution(* com.biz.impl..*.save(..))")
    public void around(ProceedingJoinPoint pjp){
    	System.out.println("======================");
    	
        String methodName=pjp.getSignature().getName();
        Object result=null;
        try {
        	 System.out.println("【環繞增強-前置】開始進入方法"+methodName);
            result=pjp.proceed();
            
        } catch (Throwable e) {
        	 System.out.println("【環繞增強-異常】"+methodName+"方法出錯了"+e.getMessage());
        }finally{
        	 System.out.println("【環繞增強-最終】"+methodName+",最終"); 
        }     
        System.out.println("【環繞增強-後置】方法執行完畢"+methodName+",返回值是"+result);
    }      
}

3.2 在spring配置文件中開啓aspectj自動代理

 <!-- 此處省略導入aop命名空間代碼 -->
         
        <!-- 1.開啓aspectj自動代理,啓用對註解的支持 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
         
        <!-- 2.創建增強類的實例 -->
    <bean id="loggerAdvice" class="com.advice.LoggerAdvice"></bean>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章