AOP的簡單介紹

逆流而上的狂浪發表於2021-10-18

1.AOP簡介

AOP面向切面程式設計,採取橫向抽取機制,取代了傳統縱向繼承體系重複性程式碼(效能監視、安全檢查、快取)

SpringAOP使用純java實現,不需要專門的編譯過程和類載入器,在執行期間以代理方式織入增強程式碼

2.AOP底層原理

AOP底層原理:代理機制

動態代理:

特點:位元組碼就是隨用隨建立,隨用隨載入

作用:不修改原始碼的基礎上對方法進行增強

分類:

基於介面的動態代理

基於子類的動態代理

Spring的代理分為兩個:JDK動態代理和CGLib動態代理

JDK是必須實現介面才能產生代理物件,而CGLib可以對任何類生成代理

代理的原理是對目標物件進行繼承代理,如果目標物件被final修飾,就無法使用CGlib代理

總而言之:在使用Spring框架時,如果類實現了介面就直接用JDK代理,如果沒有實現介面就用CGlib代理

3.AOP術語

Joinpoint(連線點): 這個連線點其實就是指得我們所用的方法,spring只支援方法型別的連線點

Pointcut(切入點):切點就是對連線點的位置進行確定,然後再切點上新增增強程式碼

Advice(增強):增強就是AOP再給一些特殊的連線點一些特殊的功能(如新增事務,和新增日誌等)

Introduction(引介):引介是通過一種特殊的通知在不修改程式碼的前提下,動態的新增代理的目標物件

Target(目標物件):代理的目標物件

Weaving(織入):是指增強應用到目標物件來建立新的代理物件的過程

Proxy(代理):就是在一個類被AOP植入增強後,就產生一個結果代理類

Aspect(切面):切入點和通知的結合

4.AOP代理使用

先匯入一個依賴:
專門管AOP代理的依賴
<dependency>
       <groupId>org.aspectjgroupId>
       <artifactId>aspectjweaverartifactId>
       <version>1.9.6version>
   dependency>
建立通知類
前置方法(before):目標方法執行之前呼叫
後置通知(after-returning):在執行方法執行之後呼叫
環繞通知(around):在目標方法之前和之後都呼叫
異常攔截(after-throwing):如果出現異常,就會呼叫
最終通知(after):在目標方法呼叫之後呼叫(無論是否出現異常都會呼叫)

AOP代理依舊有兩種方式:

配置檔案的方式和註解的方式【註解的方式也需要在配置檔案中配置aop:aspectj-autoproxy/aop:aspectj-autoproxy標籤】

 

配置檔案的方式,
<aop:pointcut expression="execution(* com.qf.service.*ServiceImpl.*(..))" id="pc"/>
   <aop:aspect ref="myAdvice" >
       
       <aop:before method="before" pointcut-ref="pc" />
       
       <aop:after-returning method="afterReturning" pointcut-ref="pc" />
       
       <aop:around method="around" pointcut-ref="pc" />
       
       <aop:after-throwing method="afterException" pointcut-ref="pc"/>
       
       <aop:after method="after" pointcut-ref="pc"/>
   aop:aspect>
aop:config>
註解方式是直接在方法前或者類前加上註解已完成配置檔案的功能
但是註解方式必須執行applicationcontext.xml檔案配置Aop代理
//通知類
@Aspect
//表示該類是一個通知類
public class MyAdvice {
   //自己設定一個切點,管理重複程式碼
@Pointcut("execution(* com.qf.service.*ServiceImpl.*(..))")
public void pc(){}
//前置通知
//指定該方法是前置通知,並制定切入點
@Before("MyAdvice.pc()")
public void before(){
System.out.println("這是前置通知!!");
}
//後置通知
@AfterReturning("execution(* com.qf.service.*ServiceImpl.*(..))")
public void afterReturning(){
System.out.println("這是後置通知(如果出現異常不會呼叫)!!");
}
//環繞通知
@Around("execution(* com.qf.service.*ServiceImpl.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("這是環繞通知之前的部分!!");
Object proceed = pjp.proceed();//呼叫目標方法
System.out.println("這是環繞通知之後的部分!!");
return proceed;
}
//異常通知
@AfterThrowing("execution(* com.qf.service.*ServiceImpl.*(..))")
public void afterException(){
System.out.println("出事啦!出現異常了!!");
}
//後置通知
@After("execution(* com.qf.service.*ServiceImpl.*(..))")
public void after(){
System.out.println("這是後置通知(出現異常也會呼叫)!!");
}
}

 


註解方式:

<bean name="userService" class="com.qf.service.UserServiceImpl" >bean>

<bean name="myAdvice" class="com.qf.annotation_aop.MyAdvice" >bean>

<aop:aspectj-autoproxy>aop:aspectj-autoproxy>