国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring AOP的實現原理

ephererid / 1122人閱讀

摘要:使用與的靜態代理不同,使用的動態代理,所謂的動態代理就是說框架不會去修改字節碼,而是在內存中臨時為方法生成一個對象,這個對象包含了目標對象的全部方法,并且在特定的切點做了增強處理,并回調原對象的方法。

AOP(Aspect Orient Programming),我們一般稱為面向方面(切面)編程,作為面向對象的一種補充,用于處理系統中分布于各個模塊的橫切關注點,比如事務管理、日志、緩存等等。AOP實現的關鍵在于AOP框架自動創建的AOP代理,AOP代理主要分為靜態代理和動態代理,靜態代理的代表為AspectJ;而動態代理則以Spring AOP為代表。本文會分別對AspectJ和Spring AOP的實現進行分析和介紹。

使用AspectJ的編譯時增強實現AOP

之前提到,AspectJ是靜態代理的增強,所謂的靜態代理就是AOP框架會在編譯階段生成AOP代理類,因此也稱為編譯時增強。

舉個實例的例子來說。首先我們有一個普通的Hello

public class Hello {
    public void sayHello() {
        System.out.println("hello");
    }

    public static void main(String[] args) {
        Hello h = new Hello();
        h.sayHello();
    }
}

使用AspectJ編寫一個Aspect

public aspect TxAspect {
    void around():call(void Hello.sayHello()){
        System.out.println("開始事務 ...");
        proceed();
        System.out.println("事務結束 ...");
    }
}

這里模擬了一個事務的場景,類似于Spring的聲明式事務。使用AspectJ的編譯器編譯

ajc -d . Hello.java TxAspect.aj

編譯完成之后再運行這個Hello類,可以看到以下輸出

開始事務 ...
hello
事務結束 ...

顯然,AOP已經生效了,那么究竟AspectJ是如何在沒有修改Hello類的情況下為Hello類增加新功能的呢?

查看一下編譯后的Hello.class

public class Hello {
    public Hello() {
    }

    public void sayHello() {
        System.out.println("hello");
    }

    public static void main(String[] args) {
        Hello h = new Hello();
        sayHello_aroundBody1$advice(h, TxAspect.aspectOf(), (AroundClosure)null);
    }
}

可以看到,這個類比原來的Hello.java多了一些代碼,這就是AspectJ的靜態代理,它會在編譯階段將Aspect織入Java字節碼中,
運行的時候就是經過增強之后的AOP對象。

public void ajc$around$com_listenzhangbin_aop_TxAspect$1$f54fe983(AroundClosure ajc$aroundClosure) {
        System.out.println("開始事務 ...");
        ajc$around$com_listenzhangbin_aop_TxAspect$1$f54fe983proceed(ajc$aroundClosure);
        System.out.println("事務結束 ...");
    }

從Aspect編譯后的class文件可以更明顯的看出執行的邏輯。proceed方法就是回調執行被代理類中的方法。

使用Spring AOP

與AspectJ的靜態代理不同,Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是在內存中臨時為方法生成一個AOP對象,這個AOP對象包含了目標對象的全部方法,并且在特定的切點做了增強處理,并回調原對象的方法。

Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理。JDK動態代理通過反射來接收被代理的類,并且要求被代理的類必須實現一個接口。JDK動態代理的核心是InvocationHandler接口和Proxy類。

如果目標類沒有實現接口,那么Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運行時動態的生成某個類的子類,注意,CGLIB是通過繼承的方式做的動態代理,因此如果某個類被標記為final,那么它是無法使用CGLIB做動態代理的。

為了驗證以上的說法,可以做一個簡單的測試。首先測試實現接口的情況。

定義一個接口

public interface Person {
    String sayHello(String name);
}

實現類

@Component
public class Chinese implements Person {

    @Timer
    @Override
    public String sayHello(String name) {
        System.out.println("-- sayHello() --");
        return name + " hello, AOP";
    }

    public void eat(String food) {
        System.out.println("我正在吃:" + food);
    }

}

這里的@Timer注解是我自己定義的一個普通注解,用來標記Pointcut。

定義Aspect

@Aspect
@Component
public class AdviceTest {

    @Pointcut("@annotation(com.listenzhangbin.aop.Timer)")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void before() {
        System.out.println("before");
    }
}

運行

@SpringBootApplication
@RestController
public class SpringBootDemoApplication {

    //這里必須使用Person接口做注入
    @Autowired
    private Person chinese;

    @RequestMapping("/test")
    public void test() {
        chinese.sayHello("listen");
        System.out.println(chinese.getClass());
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemoApplication.class, args);
    }
}

輸出

before
-- sayHello() --
class com.sun.proxy.$Proxy53

可以看到類型是com.sun.proxy.$Proxy53,也就是前面提到的Proxy類,因此這里Spring AOP使用了JDK的動態代理。

再來看看不實現接口的情況,修改Chinese

@Component
public class Chinese {

    @Timer
//    @Override
    public String sayHello(String name) {
        System.out.println("-- sayHello() --");
        return name + " hello, AOP";
    }

    public void eat(String food) {
        System.out.println("我正在吃:" + food);
    }

}

運行

@SpringBootApplication
@RestController
public class SpringBootDemoApplication {

    //直接用Chinese類注入
    @Autowired
    private Chinese chinese;

    @RequestMapping("/test")
    public void test() {
        chinese.sayHello("listen");
        System.out.println(chinese.getClass());
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemoApplication.class, args);
    }
}

輸出

before
-- sayHello() --
class com.listenzhangbin.aop.Chinese$$EnhancerBySpringCGLIB$$56b89168

可以看到類被CGLIB增強了,也就是動態代理。這里的CGLIB代理就是Spring AOP的代理,這個類也就是所謂的AOP代理,AOP代理類在切點動態地織入了增強處理。

小結

AspectJ在編譯時就增強了目標對象,Spring AOP的動態代理則是在每次運行時動態的增強,生成AOP代理對象,區別在于生成AOP代理對象的時機不同,相對來說AspectJ的靜態代理方式具有更好的性能,但是AspectJ需要特定的編譯器進行處理,而Spring AOP則無需特定的編譯器處理。

參考:

《Spring AOP 實現原理與 CGLIB 應用》

《Spring 容器AOP的實現原理——動態代理》

《AOP的底層實現-CGLIB動態代理和JDK動態代理》

我的個人博客原文。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/66098.html

相關文章

  • Spring AOP 源碼分析系列文章導讀

    摘要:在寫完容器源碼分析系列文章中的最后一篇后,沒敢懈怠,趁熱打鐵,花了天時間閱讀了方面的源碼。從今天開始,我將對部分的源碼分析系列文章進行更新。全稱是,即面向切面的編程,是一種開發理念。在中,切面只是一個概念,并沒有一個具體的接口或類與此對應。 1. 簡介 前一段時間,我學習了 Spring IOC 容器方面的源碼,并寫了數篇文章對此進行講解。在寫完 Spring IOC 容器源碼分析系列...

    張春雷 評論0 收藏0
  • 【好好面試】學完Aop,連動態代理原理都不懂?

    摘要:總結動態代理的相關原理已經講解完畢,接下來讓我們回答以下幾個思考題。 【干貨點】 此處是【好好面試】系列文的第12篇文章。文章目標主要是通過原理剖析的方式解答Aop動態代理的面試熱點問題,通過一步步提出問題和了解原理的方式,我們可以記得更深更牢,進而解決被面試官卡住喉嚨的情況。問題如下 SpringBoot默認代理類型是什么 為什么不用靜態代理 JDK動態代理原理 CGLIB動態代理...

    Keven 評論0 收藏0
  • 從源碼入手,一文帶你讀懂Spring AOP面向切面編程

    摘要:,,面向切面編程。,切點,切面匹配連接點的點,一般與切點表達式相關,就是切面如何切點。例子中,注解就是切點表達式,匹配對應的連接點,通知,指在切面的某個特定的連接點上執行的動作。,織入,將作用在的過程。因為源碼都是英文寫的。 之前《零基礎帶你看Spring源碼——IOC控制反轉》詳細講了Spring容器的初始化和加載的原理,后面《你真的完全了解Java動態代理嗎?看這篇就夠了》介紹了下...

    wawor4827 評論0 收藏0
  • 仿照 Spring 實現簡單 IOC 和 AOP - 下篇

    摘要:在上文中,我實現了一個很簡單的和容器。比如,我們所熟悉的就是在這里將切面邏輯織入相關中的。初始化的工作算是結束了,此時處于就緒狀態,等待外部程序的調用。其中動態代理只能代理實現了接口的對象,而動態代理則無此限制。 1. 背景 本文承接上文,來繼續說說 IOC 和 AOP 的仿寫。在上文中,我實現了一個很簡單的 IOC 和 AOP 容器。上文實現的 IOC 和 AOP 功能很單一,且 I...

    AlexTuan 評論0 收藏0
  • Spring】一次線上@Transational事務注解未生效原因探究

    摘要:由于的限制,無法替換被代理類已經被載入的字節碼,只能生成并載入一個新的子類作為代理類,被代理類的字節碼依然存在于中。區別于前兩者,是一種靜態代理的實現,即在編譯時或者載入類時直接修改被代理類文件的字節碼,而非運行時實時生成代理。 現象描述 上周同事發現其基于mySql實現的分布式鎖的線上代碼存在問題,代碼簡化如下: @Controller class XService { @A...

    姘存按 評論0 收藏0

發表評論

0條評論

ephererid

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<