Spring AOP

原文連接http://zhhll.icu/2020/07/26/%E6%A1%86%E6%9E%B6/spring/Spring%20AOP/java

AOP稱爲切面編程,是面向對象的一種補充,用於處理系統中分佈於各個模塊的橫切關注點,好比事務管理、日誌、緩存等。Spring AOP中使用的是動態代理。spring

Spring AOP

動態代理不會去修改字節碼,而是在內存中臨時爲方法生成一個AOP對象,這個AOP對象包含了目標對象的所有方法,而且在特定的切點作了加強處理,並回調原對象的方法。express

AOP的核心是切面,它將多個類的通用行爲封裝成可重用的模塊,該模塊含有一組API提供橫切的功能,在SpringAOP中,切面經過@Aspect註解,也可使用XML配置編程

AOP動態代理方式

Spring AOP中動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理。緩存

JDK動態代理

JDK動態代理經過反射來接收被代理的類,而且要求被代理的類必須實現一個接口,JDK代理的核心是InvocationHandler接口和Proxy類。模塊化

CGLIB代理

若是目標類沒有實現接口,那麼Spring AOP會使用CGLIB代理來動態代理目標類。CGLIB是一個代碼生成的類庫,能夠在運行時動態的生成某個類的子類(經過繼承的方式作的動態代理,若是某個類被標記爲final,沒法使用CGLIB作動態代理)代理

AOP中的概念

  • 橫切關注點 從每一個方法中抽取出來的非核心業務
  • 切面(Aspect) 封裝橫切關注點的類,被模塊化的特殊對象,每一個關注點體現爲一個通知
  • 通知(Advice) 切面須要完成的各個具體工做
  • 目標(Target) 被通知的對象
  • 代理(Proxy) 向目標對象應用通知以後建立的對象
  • 鏈接點(Joinpoint) 橫切關注點的具體體現,程序執行的某個特定位置:好比調用前、調用後、拋出異常後
  • 切點(pointCut) 每一個類都有多個鏈接點,AOP經過切點來定位到特定的鏈接點

有五種類型的AOP通知日誌

  • before 前置通知,在方法執行以前被調用 @Beforecode

  • after 後置通知,在方法執行以後調用,不管方法執行是否成功,因此後置通知沒法獲取到返回結果@Afterxml

  • after-returning 僅當方法成功完成後執行@AfterReturning

  • after-throwing 在方法拋出異常退出時執行@AfterThrowing

  • around 在方法執行以前和以後調用@Around

AOP使用方式

AOP所須要的依賴

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.3.29.RELEASE</version>
</dependency>

<!-- aspect -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.29.RELEASE</version>
</dependency>

使用註解

使用註解的時候須要在xml中配置aop:aspectj-autoproxy/

<!-- 使@Aspect註解生效 -->
<aop:aspectj-autoproxy/>
/**
* 聲明切面
*/
@Aspect
@Component
@Order(1)// 使用Order指定切面優先級  數字越小  優先級越高  越先執行
public class LoggingAspect {
		// @Before  前置通知
    // JoinPoint 能夠獲取到方法的一些信息
    @Before("execution(public String com.zhanghe.study.spring4.beans.aoptest.MyInterface.log(..))")
    public void before(JoinPoint point){
        // 獲取方法名
        String methodName = point.getSignature().getName();
        // point.getArgs()獲取參數
        System.out.println(methodName+"方法執行前,參數爲"+ Arrays.toString(point.getArgs()));
    }

    // 方法正常執行完,能夠獲取方法返回值
    // returning中配置的名字必須與第二個參數同名
    @AfterReturning(value="execution(public String com.zhanghe.study.spring4.beans.aoptest.MyInterface.log(..))",
            returning = "result")
    public void afterReturn(JoinPoint point,Object result){
        // 獲取方法名
        String methodName = point.getSignature().getName();
        System.out.println(methodName+"方法執行完成,結果爲"+ result);
    }


    // 方法出現異常
    // throwing中配置的名字必須與第二個參數同名,且能夠指定對於哪些異常進行執行  第二個參數類型能夠爲所要捕獲的異常類型
    @AfterThrowing(value="execution(public String com.zhanghe.study.spring4.beans.aoptest.MyInterface.log(..))",
            throwing = "exception")
    public void afterThrowing(JoinPoint point,Exception exception){
        // 獲取方法名
        String methodName = point.getSignature().getName();
        System.out.println(methodName+"方法執行出現異常,異常信息爲"+ exception.getMessage());
    }
}

在使用切面的時候必須保證切面是Spring IOC容器中的bean

使用XML

全部的aop配置都應該配置在<aop:config>標籤中,在xml中只須要關注切面、通知以及切入點表達式

<!-- LoggingAspect所對應的bean -->
<bean name="loggingAspect" class="com.zhanghe.study.spring4.beans.aoptest.LoggingAspect"/>

<!-- 配置AOP -->
<aop:config>
  <!-- 配置切點表達式 -->
  <aop:pointcut id="pointcut" expression="execution(public String com.zhanghe.study.spring4.beans.aoptest.MyInterface.log(..)))"/>

  <!-- 配置切面及通知 -->
  <aop:aspect ref="loggingAspect" order="1">
    <!-- 通知 -->
    <aop:before method="before" pointcut-ref="pointcut"/>
    <aop:after-returning method="afterReturn" returning="result" pointcut-ref="pointcut"/>
    <aop:after-throwing method="afterThrowing" throwing="exception" pointcut-ref="pointcut"/>
  </aop:aspect>
</aop:config>

注意:使用xml的模式進行配置記得保證切面是Spring IOC容器中的bean

因爲自己的博客百度沒有收錄,博客地址http://zhhll.icu

相關文章
相關標籤/搜索