• 當前位置:首頁 > IT技術 > 編程語言 > 正文

    spring框架-認識AOP(三)
    2021-12-13 17:45:11

    ??

    AOP綜述

    AOP是什么

    Aspect-oriented programming 面向切面(方面)編程

    AOP有什么用

    可以把業務邏輯和系統級的服務進行隔離

    系統級的服務像系統的日志,事務,權限驗證等

    AOP怎么用

    動態代理

    AOP優點

    1.降低了組件之間的耦合性 ,實現了軟件各層之間的解耦

    2、低侵入式設計,代碼的污染極低

    3、利用它很容易實現如權限攔截,運行期監控和系統日志等功能


    探索AOP

    如果沒有接觸過AOP(面向切面編程)的,可能一時間沒辦法理解,因為之前都是用JAVA的面向對象編程(OOP),沒關系,一步步跟我來學習AOP。

    當然如果您是技術大牛,既然您抽出時間查看了虛竹的文章,歡迎糾正文章中的不足和缺陷。

    我們先來看下來這段《精通Spring4.x 企業應用開發實戰》提供的代碼片段

    spring框架-認識AOP(三)_連接點

    圖上的業務代碼被事務管理代碼和性能監控代碼所包圍,而且學過JAVA的都知道,出現重復代碼了。出現重復代碼那就需要重構代碼,代碼的重構步驟一般有這兩種:

    1、抽成方法

    2、抽成類

    抽取成類的方式我們稱之為:縱向抽取

    • 通過繼承的方式實現縱向抽取

    但是,虛竹發現這種抽取方式在圖上的業務中不適用了,因為事務管理代碼和性能監控代碼是跟對應的業務代碼是有邏輯關系的


    spring框架-認識AOP(三)_aop_02

    現在縱向抽取的方式不行了,AOP希望將分散在各個業務邏輯代碼中相同的代碼通過橫向切割的方式抽取到一個獨立的模塊中!請看下圖

    ?spring框架-認識AOP(三)_動態代理_03

    圖上應該很好理解,把 重復性的非業務代碼橫向抽取出來,這個簡單。但是如何把這些非業務代碼融合到業務代碼中,達到跟之前的代碼同樣的效果。這個才是難題,就是AOP要解決的難題。



    AOP的動態代理:


    1. jdk動態代理
    2. cglib動態代理

    Spring在選擇用JDK動態代理還是CGLiB動態代理的依據:

    ?? (1)當Bean實現接口時,Spring就會用JDK的動態代理

    ?? (2)當Bean沒有實現接口時,Spring使用CGlib是實現

    (3)可以強制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)

    ?JDK代理和CGLib代理我們該用哪個

    在《精通Spring4.x 企業應用開發實戰》給出了建議:


    ??? 如果是單例的我們最好使用CGLib代理,如果是多例的我們最好使用JDK代理


    原因:

    ??? JDK在創建代理對象時的性能要高于CGLib代理,而生成代理對象的運行性能卻比CGLib的低。

    ??? 如果是單例的代理,推薦使用CGLib

    現在大家知道什么是AOP了吧:把非業務重復代碼橫向抽取出來,通過動態代理織入目標業務對象函數中,實現跟之前一樣的代碼


    AOP術語

    aop術語不好理解,《精通Spring4.x 企業應用開發實戰》書上有提到這些術語,我盡量解釋下這些術語

    連接點(JointPoint)

    一個類中的所有方法都可以被稱為連接點

    切入點(PointCut)

    上面也說了,每個方法都可以稱之為連接點,我們具體定位到某一個方法就成為切點。

    用注解來說明,被@Log定義的方法就是切入點

    spring框架-認識AOP(三)_aop_04

    增強/通知(Advice)?

    表示添加到切點的一段邏輯代碼,并定位連接點的方位信息。

    前置通知(MethodBeforeAdvice )?

    前置通知是在目標方法執行前執行

    后置通知 (AfterReturningAdvice )

    后置通知是在目標方法執行后才執行 ,可以得到目標方法返回的值 ,但不能改變返回值

    環繞通知(MethodInterceptor)

    環繞通知有在目標方法執行前的代碼,也有在目標方法執行后的代碼,可以得到目標方法的值,可以改變這個返回值!

    擴展知識點:

    spring中的攔截器分兩種:

    1、HandlerInterceptor

    2、MethodInterceptor

    HandlerInterceptor是springMVC項目中的攔截器,它攔截的目標是請求的地址,比MethodInterceptor先執行

    MethodInterceptor是AOP項目中的攔截器,它攔截的目標是方法,即使不是controller中的方法。

    異常通知(ThrowsAdvice)

    最適合的場景就是事務管理

    引介通知(IntroductionInterceptor)

    引介通知比較特殊,上面的四種通知都是在目標方法上織入通知,引介通知是在目標類添加新方法或屬性


    • 簡單來說就定義了是干什么的,具體是在哪干
    • Spring AOP提供了5種Advice類型給我們:前置通知、后置通知、返回通知、異常通知、環繞通知給我們使用!

    切面(Aspect)

    切面由切入點和增強/通知組成

    交叉在各個業務邏輯中的系統服務,類似于安全驗證,事務處理,日志記錄都可以理解為切面

    織入(weaving)

    就是將切面代碼插入到目標對象某個方法的過程,相當于我們在jdk動態代理里面的 invocationHandler接口方法的內容

    用注解解釋:就是在目標對象某個方法上,打上切面注解

    目標對象(target)

    切入點和連接點所屬的類

    顧問(Advisor)

    就是通知的一個封裝和延伸,可以將通知以更為復雜的方式織入到某些方法中,是將通知包裝為更復雜切面的裝配器。


    Spring對AOP的支持

    Spring提供了3種類型的AOP支持:


    • 基于代理的經典SpringAOP
      • 需要實現接口,手動創建代理
    • 純POJO切面
      • 使用XML配置,aop命名空間
    • ??@AspectJ??注解驅動的切面
      • 使用注解的方式,這是最簡潔和最方便的!


    知識點

    切面類型主要分成了三種


    • 一般切面
    • 切點切面
    • 引介/引入切面

    spring框架-認識AOP(三)_spring_05

    一般切面,切點切面,引介/引入切面說明:

    spring框架-認識AOP(三)_spring_06


    ?一般切面一般不會直接使用,切點切面都是直接用就可以了。

    這里重點說明下引介/引入切面:

    • 引介/引入切面是引介/引入增強的封裝器,通過引介/引入切面,可以更容易地為現有對象添加任何接口的實現!

    繼承關系圖:


    spring框架-認識AOP(三)_動態代理_07


    引介/引入切面有兩個實現類:


    • DefaultIntroductionAdvisor:常用的實現類
    • DeclareParentsAdvisor:用于實現AspectJ語言的DeclareParent注解表示的引介/引入切面

    實際上,我們使用AOP往往是Spring內部使用BeanPostProcessor幫我們創建代理。

    這些代理的創建器可以分成三類:


    • 基于Bean配置名規則的自動代理創建器:BeanNameAutoProxyCreator
    • 基于Advisor匹配機制的自動代理創建器:它會對容器所有的Advisor進行掃描,實現類為DefaultAdvisorAutoProxyCreator
    • 基于Bean中的AspectJ注解標簽的自動代理創建器:AnnotationAwareAspectJAutoProxyCreator

    對應的類繼承圖:


    spring框架-認識AOP(三)_aop_08



    使用引介/引入功能實現為Bean引入新方法?

    其實前置通知,后置通知,還是環繞通知,這些都很好理解。整個文章就引介/引入切面比較有趣,我們來實現試試吧

    有個服務員的接口:

    public interface Waiter {

    // 向客人打招呼
    void greetTo(String clientName);

    // 服務
    void serveTo(String clientName);
    }

    對應的服務員接口實現類:

    @Service("Waiter")
    public class NaiveWaiter implements Waiter {
    @Override
    public void greetTo(String clientName) {
    System.out.println("NaiveWaiter:greet to " + clientName + "...");
    }

    @Override
    public void serveTo(String clientName) {
    System.out.println("NaiveWaiter:serve to " + clientName + "...");
    }
    }

    現在我想做的就是:想這個服務員可以充當售貨員的角色,可以賣東西!當然了,我肯定不會加一個賣東西的方法到Waiter接口上啦,因為這個是暫時的~

    所以,我搞了一個售貨員接口:

    public interface Seller {

    int sell(String goods, String clientName);
    }

    售貨員接口實現類:

    public class SmartSeller implements Seller {
    @Override
    public int sell(String goods, String clientName) {
    System.out.println("SmartSeller: sell "+goods +" to "+clientName+"...");
    return 100;
    }
    }

    類圖是這樣子的:

    spring框架-認識AOP(三)_spring_09

    現在我想干的就是:借助AOP的引入/引介切面,來讓我們的服務員也可以賣東西!

    我們的引入/引介切面具體是這樣干的:

    @Component
    @Aspect
    public class EnableSellerAspect {
    @DeclareParents(value = "com.yiyu.kata.util.aop.NaiveWaiter", // 指定服務員具體的實現
    defaultImpl = SmartSeller.class) // 售貨員具體的實現
    public Seller seller; // 要實現的目標接口
    }

    ?寫了這個切面類后,大家猜猜有什么效果?

    ??????? 答案是:切面技術將SmartSeller融合到NaiveWaiter中,這樣NaiveWaiter就實現了Seller接口?。。?!

    很神奇是不是,我們來測試下

    public class TestAop {

    @Test
    public void testAop(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("dispatcher-servlet.xml","applicationContext-datasource.xml","applicationContext.xml");
    Waiter waiter = ac.getBean("Waiter",Waiter.class);

    // 調用服務員原有的方法
    waiter.greetTo("虛竹");
    waiter.serveTo("虛竹");

    // 通過引介/引入切面已經將waiter服務員實現了Seller接口,所以可以強制轉換
    Seller seller = (Seller) waiter;
    seller.sell("東西", "虛竹");

    }
    }

    結果是: 神奇吧,哈哈哈

    spring框架-認識AOP(三)_aop_10

    具體的調用過程是:

    spring框架-認識AOP(三)_連接點_11


    總結


    1. AOP的底層實現是動態代理,動態代理包含JDK動態代理和CGLib代理。當Bean實現接口時,Spring就會用JDK的動態代理;當Bean沒有實現接口時,Spring使用CGlib是實現;可以強制使用CGlib。
    2. 如果是單實例,推薦使用CGLib代理,如果是多例的我們最好使用JDK代理。因為CGLib代理對象運行速度要比JDK的代理對象要快
    3. AOP的層面是方法級別的,只能對方法進入攔截
    4. 無論是XML方式還是注解方式,原理都一樣,我們用注解AOP就夠了,簡單好用
    5. 引介/引入切面是比較有趣的,具體實現上面舉例說明了,它可以達到用某個接口的方法,又不入侵代碼,低耦合的效果。具體妙處還待開發,后面有發現再補充說明

    ?

    本文摘自 :https://blog.51cto.com/u

    開通會員,享受整站包年服務
    国产呦精品一区二区三区网站|久久www免费人咸|精品无码人妻一区二区|久99久热只有精品国产15|中文字幕亚洲无线码