你知道面試必問的AOP嗎?經過Spring又如何實現呢?

Aspect Oriented Programing 面向切面編程,相比較 oop 面向對象編程來講,Aop 關注的再也不是程序代碼中某個類,某些方法,而 aop 考慮的更多的是一種面到面的切入,即層與層之間的一種切入,因此稱之爲切面。聯想你們吃的漢堡(中間夾肉)。那麼 aop 是怎麼作到攔截整個面的功能呢?考慮學到的 servlet urlpattern /* 的配置,實際上也是 aop 的實現 。java

Spring Aop 實現的方式

  • 註解 方式
  • XML 方式

案例實操

註解方式

jar 包座標引入

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.9</version>
</dependency>

beans.xml 配置

添加命名空間spring

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

配置 Aop 代理express

<aop:aspectj-autoproxy/>

編寫 aop 實現類

/**
* 聲明切面組件
*/
@Component
@Aspect
public class LogCut {
    /**
    * 定義切入點 匹配方法規則定義
    * 匹配規則表達式含義 攔截 com.xxx.service 包下 以及子包下 全部類的全部方法
    */
    @Pointcut("execution (* com.xxx.service..*.*(..))")
    public void cut(){}
    /**
    * 聲明前置通知 並將通知應用到定義的切入點上
    * 目標類方法執行前 執行該通知
    */
    @Before(value="cut()")
    public void before(){
        System.out.println("前置通知.....");
    }
    /**
    * 聲明返回通知 並將通知應用到切入點上
    * 目標類方法執行完畢執行該通知
    */
    @AfterReturning(value="cut()")
    public void afterReturning(){
        System.out.println("返回通知....");
    }
    /**
    * 聲明最終通知 並將通知應用到切入點上
    * 目標類方法執行過程當中是否發生異常 均會執行該通知 至關於異常中的 finally 
    */
    @After(value="cut()")
    public void after(){
        System.out.println("最終通知....");
    }
    /**
    * 聲明異常通知 並將通知應用到切入點上
    * 目標類方法執行時發生異常 執行該通知
    */
    @AfterThrowing(value="cut()",throwing="e")
    public void afterThrowing(Exception e){
        System.out.println("異常通知....方法執行異常時執行:"+e);
    }
    /**
    * 聲明環繞通知 並將通知應用到切入點上
    * 方法執行先後 經過環繞通知定義相應處理
    */
    @Around(value="cut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("環繞前置...");
        System.out.println("環繞通知");
        System.out.println(pjp.getTarget()+"--"+pjp.getSignature());
        Object result=pjp.proceed();//執行目標對象方法
        System.out.println("環繞後置...");
        return result;
    } 
}

Aop 匹配方法規則表達式語言(簡要了解)

Aop 切入點表達式簡介 編程

執行任意公共方法:ide

execution(public *(..))

執行任意的 set 方法oop

execution(* set*(..))

執行 com.xxx.service 包下任意類的任意方法url

execution(* com.xxx.service.*.*(..))

執行 com.xxx.service 包 以及子包下任意類的任意方法代理

execution(* com.xxx.service..*.*(..))

xml 方式

配置切面、切入點、通知

<!-- aop 相關配置 -->
<aop:config>
    <!-- aop 切面配置 -->
    <aop:aspect ref="logCut">
        <!-- 定義 aop 切入點 -->
        <aop:pointcut expression="execution (* com.xxx.service..*.*(..))" 
        id="cut"/>
        <!-- 配置前置通知 指定前置通知方法名 並引用切入點定義 -->
        <aop:before method="before" pointcut-ref="cut"/>
        <!-- 配置返回通知 指定返回通知方法名 並引用切入點定義 -->
        <aop:after-returning method="afterReturning" pointcut-ref="cut"/>
        <!-- 配置異常通知 指定異常通知方法名 並引用切入點定義 -->
        <aop:after-throwing method="afterThrowing" throwing="e" pointcut-ref="cut"/>
        <!-- 配置最終通知 指定最終通知方法名 並引用切入點定義 -->
        <aop:after method="after" pointcut-ref="cut"/>
        <!-- 配置環繞通知 指定環繞通知方法名 並引用切入點定義 -->
        <aop:around method="around" pointcut-ref="cut"/>
    </aop:aspect>
</aop:config>

定義 bean

/**
* 聲明切面組件
*/
@Component
public class LogCut {
    public void before(){
        System.out.println("前置通知.....");
    }
    public void afterReturning(){
        System.out.println("返回通知....");
    } 
    public void after(){
        System.out.println("最終通知....");
    }
    public void afterThrowing(Exception e){
     System.out.println("異常通知....方法執行異常時執行:" + e);
    }
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("環繞前置...");
        System.out.println("環繞通知");
        System.out.println(pjp.getTarget()+"--"+pjp.getSignature());
        Object result=pjp.proceed();
        System.out.println("環繞後置...");
        return result;
    }
}

擴展

AOP 的基本概念

JoinPoint(鏈接點)【動態】

被攔截到的每一個點,spring 中指被攔截到的每個方法,spring aop 一個鏈接點即表明一個方法的執行。code

Pointcut(切入點)【靜態】

對鏈接點進行攔截的定義(匹配規則定義 規定攔截哪些方法,對哪些方法進行處理),spring 這塊有專門的表達式語言定義。xml

Advice(通知){重點}

攔截到每個鏈接點即(每個方法)先後所要作的操做

  • 前置通知(前置加強)--before() 執行方法前通知
  • 返回通知(返回加強)--afterReturning 方法正常結束返回後的通知
  • 異常拋出通知(異常拋出加強)--afetrThrow()
  • 最終通知 --after 不管方法是否發生異常,均會執行該通知
  • 環繞通知 --around 包圍一個鏈接點(join point)的通知,如方法調用。這是最強大的一種通知類型。 環繞通知能夠在方法調用先後完成自定義的行爲。它也會選擇是否繼續執行鏈接點或直接返回它們本身的返回值或拋出異常來結束執行

Aspect(切面)

切入點與通知的結合,決定了切面的定義,切入點定義了要攔截哪些類的 哪些方法,通知則定義了攔截方法後要作什麼,切面則是橫切關注點的抽象,與類類似,類是對物體特徵的抽象,切面則是橫切關注點抽象。

Target(目標對象)

被代理的目標對象

Weave(織入)

將切面應用到目標對象並生成代理對象的這個過程即爲織入(過程)。

Introduction(引入)

在不修改原有應用程序代碼的狀況下,在程序運行期爲類動態添加方法或者字段的過程稱爲引入。

相關文章
相關標籤/搜索