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

資訊專欄INFORMATION COLUMN

Spring AOP的實(shí)現(xiàn)原理

ephererid / 1117人閱讀

摘要:使用與的靜態(tài)代理不同,使用的動(dòng)態(tài)代理,所謂的動(dòng)態(tài)代理就是說框架不會(huì)去修改字節(jié)碼,而是在內(nèi)存中臨時(shí)為方法生成一個(gè)對(duì)象,這個(gè)對(duì)象包含了目標(biāo)對(duì)象的全部方法,并且在特定的切點(diǎn)做了增強(qiáng)處理,并回調(diào)原對(duì)象的方法。

AOP(Aspect Orient Programming),我們一般稱為面向方面(切面)編程,作為面向?qū)ο蟮囊环N補(bǔ)充,用于處理系統(tǒng)中分布于各個(gè)模塊的橫切關(guān)注點(diǎn),比如事務(wù)管理、日志、緩存等等。AOP實(shí)現(xiàn)的關(guān)鍵在于AOP框架自動(dòng)創(chuàng)建的AOP代理,AOP代理主要分為靜態(tài)代理和動(dòng)態(tài)代理,靜態(tài)代理的代表為AspectJ;而動(dòng)態(tài)代理則以Spring AOP為代表。本文會(huì)分別對(duì)AspectJ和Spring AOP的實(shí)現(xiàn)進(jìn)行分析和介紹。

使用AspectJ的編譯時(shí)增強(qiáng)實(shí)現(xiàn)AOP

之前提到,AspectJ是靜態(tài)代理的增強(qiáng),所謂的靜態(tài)代理就是AOP框架會(huì)在編譯階段生成AOP代理類,因此也稱為編譯時(shí)增強(qiáng)。

舉個(gè)實(shí)例的例子來說。首先我們有一個(gè)普通的Hello

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

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

使用AspectJ編寫一個(gè)Aspect

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

這里模擬了一個(gè)事務(wù)的場(chǎng)景,類似于Spring的聲明式事務(wù)。使用AspectJ的編譯器編譯

ajc -d . Hello.java TxAspect.aj

編譯完成之后再運(yùn)行這個(gè)Hello類,可以看到以下輸出

開始事務(wù) ...
hello
事務(wù)結(jié)束 ...

顯然,AOP已經(jīng)生效了,那么究竟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);
    }
}

可以看到,這個(gè)類比原來的Hello.java多了一些代碼,這就是AspectJ的靜態(tài)代理,它會(huì)在編譯階段將Aspect織入Java字節(jié)碼中,
運(yùn)行的時(shí)候就是經(jīng)過增強(qiáng)之后的AOP對(duì)象。

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

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

使用Spring AOP

與AspectJ的靜態(tài)代理不同,Spring AOP使用的動(dòng)態(tài)代理,所謂的動(dòng)態(tài)代理就是說AOP框架不會(huì)去修改字節(jié)碼,而是在內(nèi)存中臨時(shí)為方法生成一個(gè)AOP對(duì)象,這個(gè)AOP對(duì)象包含了目標(biāo)對(duì)象的全部方法,并且在特定的切點(diǎn)做了增強(qiáng)處理,并回調(diào)原對(duì)象的方法。

Spring AOP中的動(dòng)態(tài)代理主要有兩種方式,JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理。JDK動(dòng)態(tài)代理通過反射來接收被代理的類,并且要求被代理的類必須實(shí)現(xiàn)一個(gè)接口。JDK動(dòng)態(tài)代理的核心是InvocationHandler接口和Proxy類。

如果目標(biāo)類沒有實(shí)現(xiàn)接口,那么Spring AOP會(huì)選擇使用CGLIB來動(dòng)態(tài)代理目標(biāo)類。CGLIB(Code Generation Library),是一個(gè)代碼生成的類庫,可以在運(yùn)行時(shí)動(dòng)態(tài)的生成某個(gè)類的子類,注意,CGLIB是通過繼承的方式做的動(dòng)態(tài)代理,因此如果某個(gè)類被標(biāo)記為final,那么它是無法使用CGLIB做動(dòng)態(tài)代理的。

為了驗(yàn)證以上的說法,可以做一個(gè)簡(jiǎn)單的測(cè)試。首先測(cè)試實(shí)現(xiàn)接口的情況。

定義一個(gè)接口

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

實(shí)現(xiàn)類

@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注解是我自己定義的一個(gè)普通注解,用來標(biāo)記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");
    }
}

運(yùn)行

@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的動(dòng)態(tài)代理。

再來看看不實(shí)現(xiàn)接口的情況,修改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);
    }

}

運(yùn)行

@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增強(qiáng)了,也就是動(dòng)態(tài)代理。這里的CGLIB代理就是Spring AOP的代理,這個(gè)類也就是所謂的AOP代理,AOP代理類在切點(diǎn)動(dòng)態(tài)地織入了增強(qiáng)處理。

小結(jié)

AspectJ在編譯時(shí)就增強(qiáng)了目標(biāo)對(duì)象,Spring AOP的動(dòng)態(tài)代理則是在每次運(yùn)行時(shí)動(dòng)態(tài)的增強(qiáng),生成AOP代理對(duì)象,區(qū)別在于生成AOP代理對(duì)象的時(shí)機(jī)不同,相對(duì)來說AspectJ的靜態(tài)代理方式具有更好的性能,但是AspectJ需要特定的編譯器進(jìn)行處理,而Spring AOP則無需特定的編譯器處理。

參考:

《Spring AOP 實(shí)現(xiàn)原理與 CGLIB 應(yīng)用》

《Spring 容器AOP的實(shí)現(xiàn)原理——?jiǎng)討B(tài)代理》

《AOP的底層實(shí)現(xiàn)-CGLIB動(dòng)態(tài)代理和JDK動(dòng)態(tài)代理》

我的個(gè)人博客原文。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/66098.html

相關(guān)文章

  • Spring AOP 源碼分析系列文章導(dǎo)讀

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

    張春雷 評(píng)論0 收藏0
  • 【好好面試】學(xué)完Aop,連動(dòng)態(tài)代理原理都不懂?

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

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

    摘要:,,面向切面編程。,切點(diǎn),切面匹配連接點(diǎn)的點(diǎn),一般與切點(diǎn)表達(dá)式相關(guān),就是切面如何切點(diǎn)。例子中,注解就是切點(diǎn)表達(dá)式,匹配對(duì)應(yīng)的連接點(diǎn),通知,指在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動(dòng)作。,織入,將作用在的過程。因?yàn)樵创a都是英文寫的。 之前《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》詳細(xì)講了Spring容器的初始化和加載的原理,后面《你真的完全了解Java動(dòng)態(tài)代理嗎?看這篇就夠了》介紹了下...

    wawor4827 評(píng)論0 收藏0
  • 仿照 Spring 實(shí)現(xiàn)簡(jiǎn)單 IOC 和 AOP - 下篇

    摘要:在上文中,我實(shí)現(xiàn)了一個(gè)很簡(jiǎn)單的和容器。比如,我們所熟悉的就是在這里將切面邏輯織入相關(guān)中的。初始化的工作算是結(jié)束了,此時(shí)處于就緒狀態(tài),等待外部程序的調(diào)用。其中動(dòng)態(tài)代理只能代理實(shí)現(xiàn)了接口的對(duì)象,而動(dòng)態(tài)代理則無此限制。 1. 背景 本文承接上文,來繼續(xù)說說 IOC 和 AOP 的仿寫。在上文中,我實(shí)現(xiàn)了一個(gè)很簡(jiǎn)單的 IOC 和 AOP 容器。上文實(shí)現(xiàn)的 IOC 和 AOP 功能很單一,且 I...

    AlexTuan 評(píng)論0 收藏0
  • Spring】一次線上@Transational事務(wù)注解未生效原因探究

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

    姘存按 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

ephererid

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<