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

資訊專欄INFORMATION COLUMN

當(dāng)Kotlin邂逅設(shè)計(jì)模式之代理模式(二)

番茄西紅柿 / 1800人閱讀

摘要:簡述從這篇文章起,我們將繼續(xù)邂逅設(shè)計(jì)模式系列篇中的第二篇代理模式。代理模式可以說很多初級(jí)中級(jí)開發(fā)者迷惑的設(shè)計(jì)模式。首先我們需要使用類圖直觀地表示出代理模式思想。所以基于代理模式很輕松就實(shí)現(xiàn)。

簡述: 從這篇文章起,我們將繼續(xù)Kotlin邂逅設(shè)計(jì)模式系列篇中的第二篇代理模式。代理模式可以說很多初級(jí)中級(jí)開發(fā)者迷惑的設(shè)計(jì)模式。但是它確實(shí)應(yīng)用很廣,不用多說大家非常熟悉的Retrofit框架,內(nèi)部使用了動(dòng)態(tài)代理設(shè)計(jì)模式,以注解的方式簡化網(wǎng)絡(luò)請(qǐng)求參數(shù)傳遞,從而實(shí)現(xiàn)更高解耦。然而在Kotlin中有天然支持的屬性代理語法特性,可以簡化Java中代理模式實(shí)現(xiàn)的模板代理。

一、介紹

代理模式(Proxy Pattern),又稱委托模式,顧名思義就是一個(gè)對(duì)象的實(shí)現(xiàn)委托給另一個(gè)代理對(duì)象來實(shí)現(xiàn)供外部調(diào)用。

二、定義

為其他對(duì)象提供一種代理方式來控制對(duì)某個(gè)對(duì)象的訪問,從而更好地保證了該對(duì)象對(duì)外使用的透明性。

三、基本要求

1、委托對(duì)象(或者被代理對(duì)象)與代理對(duì)象需要實(shí)現(xiàn)相同的接口。

2、代理對(duì)象中保有實(shí)際的委托對(duì)象引用,外部調(diào)用的操作或行為都是代理對(duì)象在內(nèi)部交于實(shí)際的委托對(duì)象去實(shí)現(xiàn)。

3、為了內(nèi)部隱藏性,外部調(diào)用者直接和兩者共同的接口通信。

三、使用場景

當(dāng)無法或不想直接訪問某個(gè)對(duì)象或訪問某個(gè)對(duì)象存在困難時(shí)可以通過一個(gè)代理對(duì)象來間接訪問。代理可以實(shí)現(xiàn)方法增強(qiáng),比如常用的日志,緩存等;也可以實(shí)現(xiàn)方法攔截,通過代理方法修改原方法的參數(shù)和返回值

四、UML類圖

代理模式在生活中非常常見,由于最近身邊同事都在討論買房,這里就以買房中介為例來介紹我們今天的代理模式。首先我們需要使用UML類圖直觀地表示出代理模式思想。

由上面的UML的類圖可知,主要涉及到四種角色:

1、Client: 客戶類,可以看做代理模式調(diào)用的外部者

2、IPurchaseHouse: 抽象買房接口,該接口主要職責(zé)是聲明HouseOwner(實(shí)際房子擁有者)與HouseAgent(房產(chǎn)中介)的共同接口方法,該類可以是一個(gè)接口或抽象類

3、HouseOwner: 房子擁有者(房東),也就是代理模式中實(shí)際委托對(duì)象或被代理對(duì)象,外部調(diào)用者Client類就是通過代理對(duì)象(中介)間接調(diào)用實(shí)際的委托對(duì)象中定義的方法

4、HouseAgent: 房產(chǎn)中介,也就是代理模式中的代理對(duì)象,該類持有一個(gè)真實(shí)HouseOwner引用,在代理類中接口方法中調(diào)用HouseOwner方法以此來達(dá)到代理作用。

五、靜態(tài)代理

1、Java實(shí)現(xiàn)靜態(tài)代理

在Java中實(shí)現(xiàn)靜態(tài)代理還是比較簡單,只要按照上述UML中分析角色規(guī)則來定義就能輕松實(shí)現(xiàn)。這里就用Java先去實(shí)現(xiàn)上述例子:

//IPurchaseHouse: 抽象買房接口
interface IPurchaseHouse {
    void inquiryPrice();//詢價(jià)

    void visitHouse();//看房

    void payDeposit();//付定金

    void signAgreement();//簽合同

    void payMoney();//付錢

    void getHouse();//拿房
}

//HouseOwner: 房子擁有者(房東)
class HouseOwner implements IPurchaseHouse {//實(shí)現(xiàn)IPurchaseHouse共同接口
    @Override
    public void inquiryPrice() {
        System.out.println("HouseOwner提出房子價(jià)格: 200W RMB");
    }

    @Override
    public void visitHouse() {
        System.out.println("HouseOwner同意買房者來看房子");
    }

    @Override
    public void payDeposit() {
        System.out.println("HouseOwner收了買房者1W RMB定金");
    }

    @Override
    public void signAgreement() {
        System.out.println("HouseOwner與買房者簽訂合同");
    }

    @Override
    public void payMoney() {
        System.out.println("買房者付錢給HouseOwner");
    }

    @Override
    public void getHouse() {
        System.out.println("買房者拿到房子");
    }
}

//HouseAgent: 房產(chǎn)中介
class HouseAgent implements IPurchaseHouse {
    private IPurchaseHouse mHouseOwner;//具體房東HouseOwner被代理對(duì)象引用

    public HouseAgent(IPurchaseHouse houseOwner) {
        mHouseOwner = houseOwner;
    }

    @Override
    public void inquiryPrice() {
        mHouseOwner.inquiryPrice();//通過具體房東HouseOwner引用去調(diào)用inquiryPrice
    }

    @Override
    public void visitHouse() {
        mHouseOwner.visitHouse();//通過具體房東HouseOwner引用去調(diào)用visitHouse
    }

    @Override
    public void payDeposit() {
        mHouseOwner.payDeposit();//通過具體房東HouseOwner引用去調(diào)用payDeposit
    }

    @Override
    public void signAgreement() {
        mHouseOwner.signAgreement();//通過具體房東HouseOwner引用去調(diào)用signAgreement
    }

    @Override
    public void payMoney() {
        mHouseOwner.payMoney();//通過具體房東HouseOwner引用去調(diào)用payMoney
    }

    @Override
    public void getHouse() {
        mHouseOwner.getHouse();//通過具體房東HouseOwner引用去調(diào)用getHouse
    }
}

//Client客戶類
class Client {
    public static void main(String[] args) {
        IPurchaseHouse houseOwner = new HouseOwner();
        IPurchaseHouse houseAgent = new HouseAgent(houseOwner);//傳入具體被代理類實(shí)例
        houseAgent.inquiryPrice();//詢問價(jià)格
        houseAgent.visitHouse();//看房
        houseAgent.payDeposit();//支付定金
        houseAgent.signAgreement();//簽合同
        houseAgent.payMoney();//付錢
        houseAgent.getHouse();//拿房
    }
}

運(yùn)行結(jié)果:

HouseOwner提出房子價(jià)格: 200W RMB
HouseOwner同意買房者來看房子
HouseOwner收了買房者1W RMB定金
HouseOwner與買房者簽訂合同
買房者付錢給HouseOwner
買房者拿到房子

Process finished with exit code 0

這就是靜態(tài)代理具體的實(shí)現(xiàn),可能有些并不能看到代理模式所帶來的好處,看上去就像是代理類做了實(shí)際轉(zhuǎn)發(fā)調(diào)用而已。實(shí)際上有個(gè)很明顯優(yōu)點(diǎn)就是: 可以在HouseAgent類中整個(gè)流程插入一些特有的操作或行為,而不會(huì)影響內(nèi)部HouseOwner的實(shí)現(xiàn),保護(hù)內(nèi)部的實(shí)現(xiàn)。 還有一個(gè)優(yōu)點(diǎn)就是代理類在保證HouseOwner核心功能同時(shí)可以擴(kuò)展其他行為

上述結(jié)論可能有點(diǎn)抽象,假如現(xiàn)在有個(gè)不一樣需求比如A房產(chǎn)中介,在看房之前首先得簽訂一個(gè)看房協(xié)議,但是這個(gè)協(xié)議只涉及購買用戶與中介之間的協(xié)議。所以基于代理模式很輕松就實(shí)現(xiàn)。

//修改后的HouseAgentA
class HouseAgentA implements IPurchaseHouse {
    private IPurchaseHouse mHouseOwner;//具體房東HouseOwner被代理對(duì)象引用
    private boolean mIsSigned;

    public HouseAgentA(IPurchaseHouse houseOwner) {
        mHouseOwner = houseOwner;
    }

    @Override
    public void inquiryPrice() {
        mHouseOwner.inquiryPrice();//通過具體房東HouseOwner引用去調(diào)用inquiryPrice
    }

    @Override
    public void visitHouse() {
        if (mIsSigned) {
            System.out.println("您已經(jīng)簽訂了看房協(xié)議,可以看房了");
            mHouseOwner.visitHouse();//通過具體房東HouseOwner引用去調(diào)用visitHouse
        } else {
            System.out.println("很抱歉,您還沒簽訂了看房協(xié)議,暫時(shí)不能看房");
        }
    }

    public void signVisitHouseAgreement(boolean isSigned) {
        mIsSigned = isSigned;
    }

    @Override
    public void payDeposit() {
        mHouseOwner.payDeposit();//通過具體房東HouseOwner引用去調(diào)用payDeposit
    }

    @Override
    public void signAgreement() {
        mHouseOwner.signAgreement();//通過具體房東HouseOwner引用去調(diào)用signAgreement
    }

    @Override
    public void payMoney() {
        mHouseOwner.payMoney();//通過具體房東HouseOwner引用去調(diào)用payMoney
    }

    @Override
    public void getHouse() {
        mHouseOwner.getHouse();//通過具體房東HouseOwner引用去調(diào)用getHouse
    }
}
//Client客戶類
class Client {
    public static void main(String[] args) {
        IPurchaseHouse houseOwner = new HouseOwner();
        IPurchaseHouse houseAgent = new HouseAgentA(houseOwner);//傳入具體被代理類實(shí)例
        houseAgent.inquiryPrice();//詢問價(jià)格
        ((HouseAgentA) houseAgent).signVisitHouseAgreement(true);//簽訂看房合同
        houseAgent.visitHouse();//看房
        houseAgent.payDeposit();//支付定金
        houseAgent.signAgreement();//簽合同
        houseAgent.payMoney();//付錢
        houseAgent.getHouse();//拿房
    }
}

運(yùn)行結(jié)果:

HouseOwner提出房子價(jià)格: 200W RMB
您已經(jīng)簽訂了看房協(xié)議,可以看房了
HouseOwner同意買房者來看房子
HouseOwner收了買房者1W RMB定金
HouseOwner與買房者簽訂合同
買房者付錢給HouseOwner
買房者拿到房子

Process finished with exit code 0

2、Kotlin實(shí)現(xiàn)靜態(tài)代理

看到了Java中的HouseAgent和HouseAgent中代理類中實(shí)現(xiàn)轉(zhuǎn)發(fā)委托是不是有點(diǎn)無腦啊,有點(diǎn)機(jī)械,就像是在寫Java中的setter和getter方法一樣,太多的樣板代碼。這時(shí)候把它叫給Kotlin吧,它會(huì)讓你的代理類看起來更加簡潔和優(yōu)雅,因?yàn)樵贙otlin中實(shí)現(xiàn)代理模式有著天然優(yōu)勢(shì),熟悉Kotlin的小伙伴們都知道,在Kotlin中有代理獨(dú)有語法特性,通過它就能輕松實(shí)現(xiàn)代理模式。

//IPurchaseHouseKt: 抽象買房接口
interface IPurchaseHouseKt {
    fun inquiryPrice() //詢價(jià)

    fun visitHouse() //看房

    fun payDeposit() //付定金

    fun signAgreement() //簽合同

    fun payMoney() //付錢

    fun getHouse() //拿房
}
//HouseOwnerKt: 房子擁有者(房東)
class HouseOwnerKt : IPurchaseHouseKt {
    override fun inquiryPrice() {
        println("HouseOwner提出房子價(jià)格: 200W RMB")
    }

    override fun visitHouse() {
        println("HouseOwner同意買房者來看房子")
    }

    override fun payDeposit() {
        println("HouseOwner收了買房者1W RMB定金")
    }

    override fun signAgreement() {
        println("HouseOwner與買房者簽訂合同")
    }

    override fun payMoney() {
        println("買房者付錢給HouseOwner")
    }

    override fun getHouse() {
        println("買房者拿到房子")
    }
}
//HouseAgentKt: 房產(chǎn)中介. 注意了,重點(diǎn)來了,Kotlin只需要簡單一行就替代了Java代理類所有樣板代碼
class HouseAgentKt(houseOwnerKt: IPurchaseHouseKt) : IPurchaseHouseKt by houseOwnerKt//通過by關(guān)鍵字實(shí)現(xiàn)代理,省略大量的代理類中的樣板代碼,這一點(diǎn)需要get
//Client調(diào)用處
fun main(args: Array<String>) {
    val houseOwnerKt = HouseOwnerKt()
    HouseAgentKt(houseOwnerKt).run {
        inquiryPrice()//詢問價(jià)格
        visitHouse()//看房
        payDeposit()//支付定金
        signAgreement()//簽合同
        payMoney()//付錢
        getHouse()//拿房
    }
}

運(yùn)行結(jié)果:

HouseOwner提出房子價(jià)格: 200W RMB
HouseOwner同意買房者來看房子
HouseOwner收了買房者1W RMB定金
HouseOwner與買房者簽訂合同
買房者付錢給HouseOwner
買房者拿到房子

Process finished with exit code 0

可能有的小伙伴就會(huì)問了,你使用by關(guān)鍵字一下把所有的方法都給代理了,可是需要像上面新加的需求一樣,需要在某個(gè)方法調(diào)用時(shí)插入一段邏輯。這個(gè)也非常方便,只需要重寫需要改變的那個(gè)方法即可。一起來瞅瞅:

//修改后的HouseAgentAKt
class HouseAgentAKt(houseOwnerAKt: IPurchaseHouseKt) : IPurchaseHouseKt by houseOwnerAKt {
    private val mHouseOwnerAKt = houseOwnerAKt
    var mIsSigned: Boolean = false
    override fun visitHouse() {//只需要重寫visitHouse即可
        if (mIsSigned) {
            println("您已經(jīng)簽訂了看房協(xié)議,可以看房了")
            mHouseOwnerAKt.visitHouse()
        } else {
            println("很抱歉,您還沒簽訂了看房協(xié)議,暫時(shí)不能看房")
        }
    }
}
//Client調(diào)用處
fun main(args: Array<String>) {
    val houseOwnerKt = HouseOwnerKt()
    HouseAgentAKt(houseOwnerKt).run {
        mIsSigned = true
        inquiryPrice()
        visitHouse()
        payDeposit()
        signAgreement()
        payMoney()
        getHouse()
    }
}

運(yùn)行結(jié)果:

HouseOwner提出房子價(jià)格: 200W RMB
您已經(jīng)簽訂了看房協(xié)議,可以看房了
HouseOwner同意買房者來看房子
HouseOwner收了買房者1W RMB定金
HouseOwner與買房者簽訂合同
買房者付錢給HouseOwner
買房者拿到房子

Process finished with exit code 0

3、揭開Kotlin中使用by代理語法糖衣

可能就會(huì)有小伙伴問了,在Kotlin中一個(gè)by關(guān)鍵字底層到底做了什么,為什么能減少代理類中樣板代碼。

實(shí)際上,在Kotlin中代理類HouseAgentKt的超類型IPurchaseHouseKt后面的by houseOwnerKt 表示houseOwnerKt將會(huì)在HouseAgentKt中內(nèi)部存儲(chǔ),并且編譯器將自動(dòng)生成委托給houseOwnerKt的所有IPurchaseHouseKt接口方法

我們可以一起來看下反編譯后的代碼,驗(yàn)證我們的結(jié)論:

public final class HouseAgentKt implements IPurchaseHouseKt {
   // $FF: synthetic field
   private final IPurchaseHouseKt $$delegate_0;//houseOwnerKt的內(nèi)部存儲(chǔ)$$delegate_0

   public HouseAgentKt(@NotNull IPurchaseHouseKt houseOwnerKt) {
      Intrinsics.checkParameterIsNotNull(houseOwnerKt, "houseOwnerKt");
      super();
      this.$$delegate_0 = houseOwnerKt;
   }

   public void getHouse() {
      this.$$delegate_0.getHouse();//委托給$$delegate_0(也即是傳入的houseOwnerKt)getHouse方法
   }

   public void inquiryPrice() {
      this.$$delegate_0.inquiryPrice();//委托給$$delegate_0(也即是傳入的houseOwnerKt)inquiryPrice方法
   }

   public void payDeposit() {
      this.$$delegate_0.payDeposit();//委托給$$delegate_0(也即是傳入的houseOwnerKt)payDeposit方法
   }

   public void payMoney() {
      this.$$delegate_0.payMoney();//委托給$$delegate_0(也即是傳入的houseOwnerKt)payMoney方法
   }

   public void signAgreement() {
      this.$$delegate_0.signAgreement();//委托給$$delegate_0(也即是傳入的houseOwnerKt)signAgreement方法
   }

   public void visitHouse() {
      this.$$delegate_0.visitHouse();//委托給$$delegate_0(也即是傳入的houseOwnerKt)visitHouse方法
   }
}
六、動(dòng)態(tài)代理

現(xiàn)在我們需求又增加了,現(xiàn)在需要增加多個(gè)代理中介,可能有很多小伙伴就說再去按照規(guī)則增加幾個(gè)代理類就可以了。盡管Kotlin能解決Java中需要編寫很多樣板代碼的問題,但是始終還是靜態(tài)的。所謂靜態(tài)就是代理者類是需要開發(fā)者自己手動(dòng)編寫,在代碼運(yùn)行前代理類的class編譯文件就已經(jīng)存在。甚至,可能不是編譯前就能決定的代理類的個(gè)數(shù),而是在運(yùn)行時(shí)確定增加代理中介的個(gè)數(shù),面對(duì)這樣場景,靜態(tài)代理可能就無能為力,那么就引出下面的動(dòng)態(tài)代理

1、Java實(shí)現(xiàn)動(dòng)態(tài)代理

在Java中給我們提供了一個(gè)非常方便的動(dòng)態(tài)代理接口InvocationHandler,只要實(shí)現(xiàn)這個(gè)接口然后重寫它的抽象方法invoke()

//DynamicProxy類
class DynamicProxy implements InvocationHandler {
    private Object object;//被代理類的引用

    DynamicProxy(Object object) {//傳入被代理類的實(shí)例引用
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(object, args);
    }
}
//Client類
class Client {
    public static void main(String[] args) {
        IPurchaseHouse houseOwner = new HouseOwner();
        DynamicProxy dynamicProxy = new DynamicProxy(houseOwner);
        //Proxy.newProxyInstance方法動(dòng)態(tài)構(gòu)造一個(gè)代理中介,需要傳入被代理類的ClassLoader、共同接口集合和dynamicProxy實(shí)例對(duì)象
        IPurchaseHouse agentA = (IPurchaseHouse) Proxy.newProxyInstance(houseOwner.getClass().getClassLoader(), new Class[]{IPurchaseHouse.class}, dynamicProxy);
        agentA.inquiryPrice();
        agentA.visitHouse();
        agentA.payDeposit();
        agentA.signAgreement();
        agentA.payMoney();
        agentA.getHouse();
    }
}

運(yùn)行結(jié)果:

HouseOwner提出房子價(jià)格: 200W RMB
HouseOwner同意買房者來看房子
HouseOwner收了買房者1W RMB定金
HouseOwner與買房者簽訂合同
買房者付錢給HouseOwner
買房者拿到房子

Process finished with exit code 0

2、Kotlin實(shí)現(xiàn)動(dòng)態(tài)代理

實(shí)際上Java中的動(dòng)態(tài)代理實(shí)現(xiàn)已經(jīng)非常精簡了,所以在Kotlin在動(dòng)態(tài)代理實(shí)現(xiàn)并沒有特別不一樣的,它和Java的實(shí)現(xiàn)沒有不同。所以這里就不再重復(fù)實(shí)現(xiàn),只是換了Kotlin語言實(shí)現(xiàn)沒有什么不一樣的。

七、動(dòng)態(tài)代理原理解析

1、原理結(jié)論闡述

動(dòng)態(tài)代理與靜態(tài)代理不同點(diǎn)在于,它可以動(dòng)態(tài)生成任意個(gè)代理對(duì)象,無需要開發(fā)者手動(dòng)編寫代理類代碼。動(dòng)態(tài)代理機(jī)制在運(yùn)行時(shí)動(dòng)態(tài)生成代理類字節(jié)碼byte數(shù)組,然后通過jvm內(nèi)部將字節(jié)碼byte數(shù)組反序列化對(duì)應(yīng)代理的Class對(duì)象,然后再通過反射機(jī)制創(chuàng)建代理類的實(shí)例

2、源碼分析論證

1、第一步我們先從Proxy.newProxyInstance方法進(jìn)入探究,通過它在外部更為直觀是可以獲取代理類對(duì)象。

class Client {
    public static void main(String[] args) {
        IPurchaseHouse houseOwner = new HouseOwner();
        DynamicProxy dynamicProxy = new DynamicProxy(houseOwner);
        //第一步: 從Proxy.newProxyInstance方法入手
        IPurchaseHouse agentA = (IPurchaseHouse) Proxy.newProxyInstance(
                houseOwner.getClass().getClassLoader(),
                new Class[]{IPurchaseHouse.class},
                dynamicProxy
        );
        agentA.inquiryPrice();
        agentA.visitHouse();
        agentA.payDeposit();
        agentA.signAgreement();
        agentA.payMoney();
        agentA.getHouse();
    }
}

2、第二步進(jìn)入Proxy.newProxyInstance方法的定義

Proxy.newProxyInstance有三個(gè)參數(shù):

loader(ClassLoader): 這個(gè)參數(shù)是實(shí)際被代理類的類加載器實(shí)例。

interfaces(Class<);: 代理類和被代理類共同實(shí)現(xiàn)的接口的Class數(shù)組

h(InvocationHandler): 代理攔截器接口,一般需要使用子類去實(shí)現(xiàn)該接口或匿名類去實(shí)現(xiàn)

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<);
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);
       
        final Class<);//將interfaces的Class數(shù)組clone一份副本,賦值給intfs
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {//檢查創(chuàng)建一個(gè)新的代理類需要權(quán)限
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
         //注意點(diǎn)1: getProxyClass0方法拿到代理類的Class對(duì)象實(shí)例cl
         //注意傳入的參數(shù)就是從外部傳入的loader(被代理類的類加載器)、intfs(被代理類實(shí)現(xiàn)所接口的Class[]的副本)
        Class<);/*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            
            //注意點(diǎn)2: 拿到cl實(shí)例后,就通過反射機(jī)制創(chuàng)建代理類實(shí)例
            final Constructor<);//先拿到代理類的構(gòu)造器Constructor實(shí)例cons
            final InvocationHandler ih = h;
            //檢查代理類構(gòu)造器是否是公有的public權(quán)限, 不是就會(huì)通過AccessController去修改訪問權(quán)限以致于可以創(chuàng)建代理類實(shí)例
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        cons.setAccessible(true);//將訪問權(quán)限設(shè)置為可訪問的
                        return null;
                    }
                });
            }
            //注意點(diǎn)3: 拿到構(gòu)造器實(shí)例cons后,就到了最為關(guān)鍵的也就是最后一步,創(chuàng)建代理類實(shí)例。
            //但是需要注意的是構(gòu)造器反射傳入的參數(shù)是h,也就是傳入的InvocationHandler的實(shí)例,也可以進(jìn)一步推論生成的代理類中存在以InvocationHandler為參數(shù)的構(gòu)造器。
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

再一次來梳理下newProxyInstance源碼流程:

首先傳入loaderinterfacesh三個(gè)參數(shù),先將interfacesclone一份副本保存在intfs中,然后檢查創(chuàng)建一個(gè)新的代理類所需要的權(quán)限,接著到了我們第一個(gè)注意點(diǎn)1,就是通過getProxyClass0方法(需要傳入loaderintfs參數(shù))獲得代理類的Class對(duì)象實(shí)例。拿到了代理類實(shí)例后,我們就通過反射的機(jī)制創(chuàng)建代理類實(shí)例

到了我們的注意點(diǎn)二,通過代理類Class對(duì)象cl獲得構(gòu)造器對(duì)象cons,并檢查構(gòu)造器對(duì)象是否是public,否則就強(qiáng)行修改訪問權(quán)限

最后到了注意點(diǎn)三,通過cons.newInstance創(chuàng)建代理類對(duì)象,并且構(gòu)造器反射中傳入h(InvocationHandler對(duì)象),說明我們可以推斷一下生成的代理類中存在以InvocationHandler為參數(shù)的構(gòu)造器

3、第三步進(jìn)入getProxyClass0方法,傳入的參數(shù)loaderintfs,在該方法內(nèi)部會(huì)委托給proxyClassCache的get方法,如果給定的類加載器中定義的代理類實(shí)現(xiàn)了給定的接口,直接返回緩存中的副本,否則它將通過ProxyClassFactory創(chuàng)建代理類.

    private static Class<);if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        //請(qǐng)注意上面那段英文注釋: 如果給定的類加載器中定義的代理類實(shí)現(xiàn)了給定的接口,
        //那么就會(huì)直接返回緩存中的副本,否則它將通過ProxyClassFactory創(chuàng)建代理類
        //注意點(diǎn)1: proxyClassCache;注意點(diǎn)2: ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

4、第四步proxyClassCache的介紹和定義, 請(qǐng)注意創(chuàng)建proxyClassCache傳入的構(gòu)造器兩個(gè)參數(shù)分別是: KeyFactoryProxyClassFactory

    /**
     * a cache of proxy classes
     */
    private static final WeakCachenew WeakCache<>(new KeyFactory(), new ProxyClassFactory());

proxyClassCache是一個(gè)WeakCache對(duì)象,WeakCache中的K表示key值,P代表參數(shù),V代表存儲(chǔ)的值。此類用于緩存(key, sub-key) -> value鍵值對(duì)。內(nèi)部具體實(shí)現(xiàn)是借助了ConcurentMap>>,Supplier是一個(gè)接口,就一個(gè)get方法用于獲得值,不過是泛型V的包裝類,第一個(gè)Object就是key(這里表達(dá)式不用泛型K是因?yàn)閗ey值可以為null),第二個(gè)就是sub-key,那么它對(duì)應(yīng)著什么呢);P呢,這就需要引出另外一個(gè)函數(shù)接口BiFunction,該接口內(nèi)部存在R apply(T t, U u)方法,這個(gè)方法意思就是根據(jù)傳入兩個(gè)泛型TU的值經(jīng)過一定計(jì)算得到泛型R的值。在WeakCache類中存在兩個(gè)BiFunction對(duì)象:

final class WeakCache<K, P, V> {
    private final ReferenceQueue refQueue
        = new ReferenceQueue<>();
    // the key type is Object for supporting null key
    private final ConcurrentMap>> map
        = new ConcurrentHashMap<>();
    private final ConcurrentMap, Boolean> reverseMap
        = new ConcurrentHashMap<>();
    private final BiFunctionprivate final BiFunction valueFactory;
    
    public WeakCache(BiFunction {
        //根據(jù)K,P得到sub-key算法
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        //根據(jù)K,P得到value算法
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }
    ...
}    

WeakCahe類中只有一個(gè)核心get方法,里面包含了整個(gè)緩存的邏輯,注意我們獲取代理類Class對(duì)象,就是通過proxyClassCache.get(loader, interfaces);實(shí)際上就是調(diào)用WeakCache中的get方法.

//K泛型是一級(jí)map的緩存key, P泛型傳入的參數(shù),分別對(duì)應(yīng)外部傳入的 loader和 interfaces
public V get(K key, P parameter) {
        ...
        //通過傳入一級(jí)map的key,通過CacheKey拿到最終
        Object cacheKey = CacheKey.valueOf(key, refQueue);
        // 懶初始化cacheKey對(duì)應(yīng)的二級(jí)valuesMap, 如果valuesMap為空,就會(huì)新創(chuàng)建一個(gè)空的ConcurrentMap的valueMap,put到一級(jí)緩存map中
        ConcurrentMap> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
        //如果valuesMap為空,就會(huì)新創(chuàng)建一個(gè)空的ConcurrentMap的valueMap
            ConcurrentMap> oldValuesMap = map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>());
            //如果內(nèi)部已經(jīng)存在原來的oldValuesMap直接用它
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

 //------注意點(diǎn)1: subKeyFactory.apply(key, parameter)-----
        //根據(jù)傳入的一級(jí)map的key和參數(shù)parameter,通過subKeyFactory中的apply方法獲得sub-key,
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        //然后通過我們的sub-key,從二級(jí)緩存的valuesMap中取的supplier對(duì)象
        Supplier supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            if (supplier != null) {
                //supplier這個(gè)對(duì)象可能是Factory或CacheValue對(duì)象,
                //那么也就是supplier.get()方法可能是調(diào)用了Factory中的get方法或CacheValue中的get方法
//--------注意點(diǎn)2: supplier.get()-----            
                V value = supplier.get();
                //如果value不為空就返回value,結(jié)束整個(gè)get方法調(diào)用
                if (value != null) {
                    return value;
                }
            }
            //如果緩存中沒有supplier對(duì)象
            //或者supplier中g(shù)et返回是null
            //或者Factory對(duì)象沒有在CacheValue中被成功創(chuàng)建
            
            //factory為null,就會(huì)創(chuàng)建一個(gè)新的Factory實(shí)例
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            //supplier為null
            if (supplier == null) {
                //根據(jù)新創(chuàng)建的factory和subKey拿到supplier對(duì)象,如果valuesMap中存在subKey, factory鍵值對(duì),就返回已經(jīng)存在的值,沒有直接返回null
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                 //如果拿到supplier為null,supplier就變?yōu)榱薴actory,這就是前面說supplier為一個(gè)factory   
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    supplier = factory;
                } else {
                    //通過valuesMap.get()拿到supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

我們來一起梳理下WeakCache的邏輯: 首先proxyClassCache就是一個(gè)WeakCache實(shí)例對(duì)象,它有兩個(gè)構(gòu)造器參數(shù)subKeyFactoryvalueFactory,創(chuàng)建proxyClassCache實(shí)例對(duì)應(yīng)傳入的是proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory())中的KeyFactoryProxyClassFactory.

然后在WeakCache內(nèi)部存在二級(jí)ConcurrentHashMap, 一級(jí)map的key就是get方法傳入的key, 通過這個(gè)key拿到cacheKey,從而拿到對(duì)應(yīng)的valuesMap二級(jí)map

然后又通過根據(jù)傳入的一級(jí)map的key和參數(shù)parametersubKeyFactory中的apply方法獲得sub-key,通過sub-key拿到二級(jí)map中存儲(chǔ)的Supplier對(duì)象,它可能是一個(gè)CacheValue也有可能是一個(gè)Factory,

最終通過Factoryget方法拿到實(shí)際的值。

對(duì)于上述有兩個(gè)核心注意點(diǎn)

注意點(diǎn)1----->獲取subKey過程: 通過subKeyFactory.apply(key,parameter)拿到sub-key

//weakCache調(diào)用處: 
 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
 //KeyFactory的定義
    private static final class KeyFactory
        implements BiFunction

注意點(diǎn)2----> supplier.get()獲取value的過程:

我們都知道supplier對(duì)應(yīng)的可以是Factory對(duì)象,也就是最后會(huì)調(diào)用Factory中的get方法。

  @Override
        public synchronized V get() { // serialize access
            // 再一次檢查supplier,如果傳入從valuesMap拿到的不等于當(dāng)前Factory對(duì)象,因?yàn)樗赡芤呀?jīng)變成CacheValue了,那就直接返回null
            Supplier supplier = valuesMap.get(subKey);
            if (supplier != this) {
                return null;
            }
            
            //創(chuàng)建一個(gè)新的value
            V value = null;
            try {
               //注意點(diǎn)出現(xiàn),value最終會(huì)通過valueFactory.apply(key, parameter)拿到
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { // remove us on failure
                    valuesMap.remove(subKey, this);
                }
            }
            // 判斷value是否為null
            assert value != null;

            // 將拿到的value包裝成一個(gè)CacheValue
            CacheValue cacheValue = new CacheValue<>(value);

            // 嘗試把valuesMap中的對(duì)應(yīng)subKey的Factory替換成cacheValue,
            //這就是為什么前面說過valuesMap中取出的Supplier可能是Factory可能是CacheValue,有沒有種偷梁換柱的趕腳
            if (valuesMap.replace(subKey, this, cacheValue)) {
                //替換成功后,并把cacheValue put到reverseMap中
                reverseMap.put(cacheValue, Boolean.TRUE);
            } else {
                throw new AssertionError("Should not reach here");
            }

            // 成功替換了新的CacheValue,并返回最終的值
            return value;
        }

通過上述代碼分析,我們知道最終value獲取是來自于valueFactoryapply方法,還記得valueFactory是啥嗎?沒錯(cuò)它就是ProxyClassFactory也就是最終定位到了ProxyClassFactory中的apply方法。這也就是為什么之前說如果緩存中有直接從緩存中返回緩存的副本,沒有就在ProxyClassFactory中創(chuàng)建代理對(duì)象。

5、第五步進(jìn)入ProxyClassFactory中的apply方法進(jìn)行探究,這是創(chuàng)建新的代理類Class對(duì)象唯一來源。

    private static final class ProxyClassFactory
        implements BiFunction

再重新梳理一下ProxyClassFactory中的apply中的邏輯,首先做一些接口驗(yàn)證操作,然后通過ProxyGenerator.generateProxyClass生成確定的代理類Class文件的byte數(shù)組,最后通過defineClass0方法傳入被代理類的類加載器、代理類唯一名稱、生成的代理類文件反序列化成一個(gè)代理類的Class對(duì)象

6、第六步進(jìn)入ProxyGenerator中的generateProxyClass方法進(jìn)行探究,主要通過它來生成代理類Class文件。generateProxyClass方法傳入的參數(shù)主要有: proxyName(唯一代理類名稱), interfaces(需要代理的接口Class數(shù)組), accessFlags(訪問權(quán)限標(biāo)識(shí))

    public static byte[] generateProxyClass(final String var0, Class<);int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        //-----注意點(diǎn)----調(diào)用ProxyGenerator中的generateClassFile方法
        final byte[] var4 = var3.generateClassFile();
        //是否需要把生成Class文件保存在本地文件中,這個(gè)標(biāo)識(shí)可以從外部進(jìn)行配置
        //boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"))
        if (saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction() {
                public Void run() {
                    try {
                        int var1 = var0.lastIndexOf(46);
                        Path var2;
                        if (var1 > 0) {
                            Path var3 = Paths.get(var0.substring(0, var1).replace(., File.separatorChar));
                            Files.createDirectories(var3);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class");
                        }

                        Files.write(var2, var4, new OpenOption[0]);
                        return null;
                    } catch (IOException var4x) {
                        throw new InternalError("I/O exception saving generated file: " + var4x);
                    }
                }
            });
        }

        return var4;
    }

7、第七步進(jìn)入generateClassFile()方法,該方法主要生成Class文件。

 private byte[] generateClassFile() {
        //---注意點(diǎn)1----在生成的代理類中加入Object類幾個(gè)默認(rèn)方法比如常見的hashCode、equal、toString方法
        this.addProxyMethod(hashCodeMethod, Object.class);
        this.addProxyMethod(equalsMethod, Object.class);
        this.addProxyMethod(toStringMethod, Object.class);
        //取出代理類的接口的Class數(shù)組
        Class[] var1 = this.interfaces;
        int var2 = var1.length;

        int var3;
        Class var4;
        //----注意點(diǎn)2---遍歷代理類的接口的Class數(shù)組,將代理類接口中的方法加入生成的代理類中
        for(var3 = 0; var3 < var2; ++var3) {
            var4 = var1[var3];
            //獲得每個(gè)接口中定義的所有方法Method對(duì)象
            Method[] var5 = var4.getMethods();
            int var6 = var5.length;
            //然后再遍歷所有的Method對(duì)象,并把它加入到生成的代理類中
            for(int var7 = 0; var7 < var6; ++var7) {
                Method var8 = var5[var7];
                this.addProxyMethod(var8, var4);
            }
        }
        ...
        try {
        //----注意點(diǎn)3 生成的代理類中加入生成構(gòu)造器方法generateConstructor----
            this.methods.add(this.generateConstructor());
            var11 = this.proxyMethods.values().iterator();
            ...
       //----注意點(diǎn)4 生成的代理類中加入生成靜態(tài)初始化塊----
            this.methods.add(this.generateStaticInitializer());
        } catch (IOException var10) {
            throw new InternalError("unexpected I/O Exception", var10);
        }
         
            ...
            //創(chuàng)建字節(jié)數(shù)組輸出流
            ByteArrayOutputStream var13 = new ByteArrayOutputStream();
            DataOutputStream var14 = new DataOutputStream(var13);

            try {
                ...
                var14.writeShort(this.fields.size());
                var15 = this.fields.iterator();
                //往輸出流寫入生成代理類Filed字段相關(guān)信息
                while(var15.hasNext()) {
                    ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                    var20.write(var14);
                }

                var14.writeShort(this.methods.size());
                var15 = this.methods.iterator();
                //往輸出流寫入生成代理類Method方法相關(guān)信息
                while(var15.hasNext()) {
                    ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                    var21.write(var14);
                }

                var14.writeShort(0);
                //返回最終的Class文件的字節(jié)數(shù)組
                return var13.toByteArray();
            } catch (IOException var9) {
                throw 
                 
               
              

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

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

相關(guān)文章

  • Kotlin + Spring Boot服務(wù)端開發(fā)

    摘要:是什么著名廠商開發(fā)的基于的靜態(tài)類型編程語言,聲稱。語法近似和,且已活躍在開發(fā)領(lǐng)域,被譽(yù)為平臺(tái)的。各有千秋,我更認(rèn)同改寫字節(jié)碼。的作用是防止敏感字段被泄露到中,的作用是軟刪除數(shù)據(jù)不可見,但沒有真的刪除。 Kotlin是什么? 著名IDE廠商JetBrains開發(fā)的基于JVM的靜態(tài)類型編程語言,聲稱100%?interoperable?with?Java。Kotlin是由工程師設(shè)計(jì)的,各種...

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

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

0條評(píng)論

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