成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java 代理模式與 AOP

jk_v1 / 443人閱讀

摘要:本文首發(fā)于作者最近在學(xué),研究了下和代理模式,寫(xiě)點(diǎn)心得和大家分享下。所以下面來(lái)重點(diǎn)分析下代理模式。這里代理模式分為靜態(tài)代理和動(dòng)態(tài)代理兩種,我們分別來(lái)看下。代理模式,代理,意味著有一方代替另一方完成一件事。

本文首發(fā)于 https://jaychen.cc
作者 jaychen

最近在學(xué) Spring,研究了下 AOP 和代理模式,寫(xiě)點(diǎn)心得和大家分享下。

AOP

先說(shuō)下AOP,AOP 全稱 Aspect Oriented Programming,面向切面編程,和 OOP 一樣也是一種編程思想。AOP 出現(xiàn)的原因是為了解決 OOP 在處理 侵入性業(yè)務(wù)上的不足。

那么,什么是侵入性業(yè)務(wù)?類似日志統(tǒng)計(jì)、性能分析等就屬于侵入性業(yè)務(wù)。本來(lái)原本的業(yè)務(wù)邏輯代碼優(yōu)雅大氣,正常運(yùn)行,突然說(shuō)需要在這段邏輯里面加上性能分析,于是代碼就變成了下面這個(gè)樣子

long begin = System.currentTimeMillis(); 

// 原本的業(yè)務(wù)
doSomething();

long end = System.currentTimeMillis();
long step = end - begin;
System.out.println("執(zhí)行花費(fèi) :" + step);

從上面的代碼看到,性能分析的業(yè)務(wù)代碼和原本的業(yè)務(wù)代碼混在了一起,好端端的代碼就這么被糟蹋了。所以,侵入性業(yè)務(wù)必須有一個(gè)更好的解決方案,這個(gè)解決方案就是 AOP。

那么,AOP 是如何解決這類問(wèn)題?

代理模式

通常,我們會(huì)使用代理模式來(lái)實(shí)現(xiàn) AOP,這就意味著代理模式可以優(yōu)雅的解決侵入性業(yè)務(wù)問(wèn)題。所以下面來(lái)重點(diǎn)分析下代理模式。

這個(gè)是代理模式的類圖。很多人可能看不懂類圖,但是說(shuō)實(shí)話有時(shí)候一圖勝千言,這里稍微解釋下類圖的含義,尤其是類圖中存在的幾種連線符。

矩形代表一個(gè)類,矩形內(nèi)部的信息有:類名,屬性和方法。

虛線 + 三角空心箭頭為 is=a 的關(guān)系,表示繼承,所以上圖中 TestSQLPerformance 都實(shí)現(xiàn) IDatabase 接口。

實(shí)線 + 箭頭為關(guān)聯(lián)關(guān)系,一般在代碼中以成員變量的形式體現(xiàn),所以上圖中 Performance 類有一個(gè) TestSQL 的成員變量。

有了類圖,我們可以根據(jù)類圖直接寫(xiě)出代理模式的代碼了。這里代理模式分為靜態(tài)代理和動(dòng)態(tài)代理兩種,我們分別來(lái)看下。

靜態(tài)代理

假設(shè)一個(gè)場(chǎng)景,我們需要測(cè)試一條 sql query 執(zhí)行所花費(fèi)的時(shí)間。

如果按照普通的方式,代碼邏輯應(yīng)該如下

long begin = System.currentTimeMillis(); 

query();

long end = System.currentTimeMillis();
long step = end - begin;
System.out.println("執(zhí)行花費(fèi) :" + step);

上面說(shuō)過(guò)了,這種會(huì)導(dǎo)致查詢邏輯和性能測(cè)試邏輯混淆在一塊,那么來(lái)看看使用代理模式是如何解決這個(gè)問(wèn)題的。

代理模式,代理,意味著有一方代替另一方完成一件事。這里,我們會(huì)編寫(xiě)兩個(gè)類:TestSQL 為query 執(zhí)行邏輯,Performance 為性能測(cè)試類。這里 Performance 會(huì)代替 TestSQL 去執(zhí)行 query 邏輯。

要想 Performance 能夠代替 TestSQL 執(zhí)行 query 邏輯,那么這兩個(gè)類應(yīng)該是有血緣關(guān)系的,即這兩個(gè)必須實(shí)現(xiàn)同一個(gè)接口。

// 接口
public interface IDatabase {
    void query();
}


public class TestSQL implements IDatabase {

    @Override
    public void query() {
        System.out.println("執(zhí)行 query。。。。");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


// 代理類
public class PerformanceMonitor implements IDatabase {
    TestSQL sql;

    public PerformanceMonitor(TestSQL sql) {
        this.sql = sql;
    }


    @Override
    public void query() {
        long begin = System.currentTimeMillis();

        // 業(yè)務(wù)邏輯。
        sql.query();

        long end = System.currentTimeMillis();
        long step = end - begin;
        System.out.println("執(zhí)行花費(fèi) : " + step);
    }
}


// 測(cè)試代碼
public class Main {
    public static void main(String[] strings) {
        TestSQL sql = new TestSQL();

        PerformanceMonitor performanceMonitor = new PerformanceMonitor(sql);
        // 由 Performance 代替 testSQL 執(zhí)行
        performanceMonitor.query();
    }
}

從上面的示例代碼可以分析出來(lái)代理模式是如何運(yùn)作的,這里我們可以很明顯看出代理模式的優(yōu)越性,TestSQL 的邏輯很純粹,沒(méi)有混入其他無(wú)關(guān)的業(yè)務(wù)代碼。

動(dòng)態(tài)代理

回顧靜態(tài)代理的代碼,發(fā)現(xiàn)代理類 Performance 必須實(shí)現(xiàn) IDatabase 接口。如果有很多業(yè)務(wù)需要用到代理來(lái)實(shí)現(xiàn),那么每個(gè)業(yè)務(wù)都需要定義一個(gè)代理類,這會(huì)導(dǎo)致類迅速膨脹,為了避免這點(diǎn),Java 提供了動(dòng)態(tài)代理。

為何稱之為動(dòng)態(tài)代理,動(dòng)態(tài)代理底層是使用反射實(shí)現(xiàn)的,是在程序運(yùn)行期間動(dòng)態(tài)的創(chuàng)建接口的實(shí)現(xiàn)。在靜態(tài)代理中,我們需要在編碼的時(shí)候編寫(xiě) Performance 類實(shí)現(xiàn) IDatabase 接口。而使用動(dòng)態(tài)代理,我們不必編寫(xiě) Performance 實(shí)現(xiàn) IDatabase 接口,而是 JDK 在底層通過(guò)反射技術(shù)動(dòng)態(tài)創(chuàng)建一個(gè) IDatabase 接口的實(shí)現(xiàn)。

使用動(dòng)態(tài)代理需要使用到 InvocationHandlerProxy 這兩個(gè)類。

// 代理類,不再實(shí)現(xiàn) IDatabase 接口,而是實(shí)現(xiàn) InvocationHandler 接口
public class Performance implements InvocationHandler {

    private TestSQL sql;

    public Performance(TestSQL sql) {
        this.sql = sql;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long begin = System.currentTimeMillis();

        // method.invoke 實(shí)際上就是調(diào)用 sql.query()
        Object object = method.invoke(sql, args);

        long end = System.currentTimeMillis();
        long step = end - begin;
        System.out.println("執(zhí)行花費(fèi) :" + step);
        return object;
    }
}



public class Main {
    public static void main(String[] strings) {
        TestSQL sql = new TestSQL();
        Performance performance = new Performance(sql);

        IDatabase proxy = (IDatabase) Proxy.newProxyInstance(
                sql.getClass().getClassLoader(),
                sql.getClass().getInterfaces(),
                performance
        );
        proxy.query();
    }
}

先來(lái)看看 newProxyInstance 函數(shù),這個(gè)函數(shù)的作用就是用來(lái)動(dòng)態(tài)創(chuàng)建一個(gè)代理對(duì)象的類,這個(gè)函數(shù)需要三個(gè)參數(shù):

第一個(gè)參數(shù)為類加載器,如果不懂是什么玩意,先套著模板寫(xiě),等我寫(xiě)下一篇文章拯救你。

第二個(gè)參數(shù)為要代理的接口,在這個(gè)例子里面就是 IDatabase 接口。

第三個(gè)參數(shù)為實(shí)現(xiàn) InvocationHandler 接口的對(duì)象。

執(zhí)行 newProxyInstance 之后,Java 會(huì)在底層自動(dòng)生成一個(gè)代理類,其代碼大概如下:

public final class $Proxy1 extends Proxy implements IDatabase{
    private InvocationHandler h;

    private $Proxy1(){}

    public $Proxy1(InvocationHandler h){
        this.h = h;
    }

    public void query(){
        ////創(chuàng)建method對(duì)象
        Method method = Subject.class.getMethod("query");
        //調(diào)用了invoke方法
        h.invoke(this, method, new Object[]{}); 
    }
}

你會(huì)發(fā)現(xiàn),這個(gè)類很像在靜態(tài)代理中的 Performance 類,是的,動(dòng)態(tài)代理其本質(zhì)是 Java 自動(dòng)為我們生成了一個(gè) $Proxy1 代理類。在 mian 函數(shù)中 newProxyInstance 的返回值就是該類的一個(gè)實(shí)例。并且,$Proxy1 中的 h 屬性就是 newProxyInstance 的第三個(gè)參數(shù)。所以,當(dāng)我們?cè)?main 函數(shù)中執(zhí)行 proxy.query(),實(shí)際上是調(diào)用 $proxy1#query 方法,進(jìn)而再調(diào)用 Performance#invoke 方法。而在 Performance#invoke 通過(guò) Object object = method.invoke(sql, args); 調(diào)用了 TestSQL#query 方法。

回顧上面的流程,理解動(dòng)態(tài)代理的核心在于理解 Java 自動(dòng)生成的代理類。這里還有一點(diǎn)要說(shuō)明,JDK 的動(dòng)態(tài)代理有一個(gè)不足:它只能為接口創(chuàng)建代理實(shí)例。這句話體現(xiàn)在代碼上就是 newProxyInstance 的第二個(gè)參數(shù)是一個(gè)接口數(shù)組。為什么會(huì)存在這個(gè)不足?其實(shí)看 $Proxy1 代理類就知道了,這個(gè)由 JDK 生成的代理類需要繼承 Proxy 類,而 Java 只支持單繼承,所以就限制了 JDK 的動(dòng)態(tài)代理只能為接口創(chuàng)建代理。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/70430.html

相關(guān)文章

  • Java設(shè)計(jì)模式綜合運(yùn)用(動(dòng)態(tài)代理+Spring AOP)

    摘要:動(dòng)態(tài)代理的核心是接口和類。以上結(jié)果說(shuō)明它生成的代理類為,說(shuō)明是代理。測(cè)試前提實(shí)現(xiàn)接口測(cè)試類使用接口方式注入代理方式必須以接口方式注入測(cè)試配置為,運(yùn)行結(jié)果如下實(shí)際校驗(yàn)邏輯。。。。 本文也同步發(fā)布至簡(jiǎn)書(shū),地址:https://www.jianshu.com/p/f70... AOP設(shè)計(jì)模式通常運(yùn)用在日志,校驗(yàn)等業(yè)務(wù)場(chǎng)景,本文將簡(jiǎn)單介紹基于Spring的AOP代理模式的運(yùn)用。 1. 代理模...

    王晗 評(píng)論0 收藏0
  • 慕課網(wǎng)_《探秘Spring AOP》學(xué)習(xí)總結(jié)

    時(shí)間:2017年09月03日星期日說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com 教學(xué)源碼:https://github.com/zccodere/s...學(xué)習(xí)源碼:https://github.com/zccodere/s... 第一章:課程介紹 1-1 面向切面 課程章節(jié) 概覽 AOP使用 AOP原理 AOP開(kāi)源運(yùn)用 課程實(shí)戰(zhàn) 課程總結(jié) 面向切面編程是一種...

    Tony_Zby 評(píng)論0 收藏0
  • 漫談代理模式

    摘要:而在模式中角色與角色的接口是相同的透明性。而在模式中與增加新功能相比它更注重通過(guò)設(shè)置代理人的方式來(lái)減輕本人的工作負(fù)擔(dān) 本文首發(fā)于泊浮目的專欄:https://segmentfault.com/blog... 前言 代理模式是在編程中非常常見(jiàn)的設(shè)計(jì)模式.筆者在面試的過(guò)程中也經(jīng)常會(huì)問(wèn)到相關(guān)的問(wèn)題,但是很多同學(xué)答的并不盡人意.在這篇文章中,筆者想和大家聊聊代理模式的應(yīng)用及一些實(shí)踐. Wha...

    neuSnail 評(píng)論0 收藏0
  • Spring AOP就是這么簡(jiǎn)單啦

    摘要:是一種特殊的增強(qiáng)切面切面由切點(diǎn)和增強(qiáng)通知組成,它既包括了橫切邏輯的定義也包括了連接點(diǎn)的定義。實(shí)際上,一個(gè)的實(shí)現(xiàn)被拆分到多個(gè)類中在中聲明切面我們知道注解很方便,但是,要想使用注解的方式使用就必須要有源碼因?yàn)槲覀円? 前言 只有光頭才能變強(qiáng) 上一篇已經(jīng)講解了Spring IOC知識(shí)點(diǎn)一網(wǎng)打盡!,這篇主要是講解Spring的AOP模塊~ 之前我已經(jīng)寫(xiě)過(guò)一篇關(guān)于AOP的文章了,那篇把比較重要的知...

    Jacendfeng 評(píng)論0 收藏0
  • 面試官:“談?wù)凷pring中都用到了那些設(shè)計(jì)模式?”。

    摘要:會(huì)一直完善下去,歡迎建議和指導(dǎo),同時(shí)也歡迎中用到了那些設(shè)計(jì)模式中用到了那些設(shè)計(jì)模式這兩個(gè)問(wèn)題,在面試中比較常見(jiàn)。工廠設(shè)計(jì)模式使用工廠模式可以通過(guò)或創(chuàng)建對(duì)象。 我自己總結(jié)的Java學(xué)習(xí)的系統(tǒng)知識(shí)點(diǎn)以及面試問(wèn)題,已經(jīng)開(kāi)源,目前已經(jīng) 41k+ Star。會(huì)一直完善下去,歡迎建議和指導(dǎo),同時(shí)也歡迎Star: https://github.com/Snailclimb... JDK 中用到了那...

    Astrian 評(píng)論0 收藏0

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

0條評(píng)論

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