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>