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

資訊專(zhuān)欄INFORMATION COLUMN

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

番茄西紅柿 / 1892人閱讀

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

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

一、介紹

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

二、定義

為其他對(duì)象提供一種代理方式來(lái)控制對(duì)某個(gè)對(duì)象的訪問(wèn),從而更好地保證了該對(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)用者直接和兩者共同的接口通信。

三、使用場(chǎng)景

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

四、UML類(lèi)圖

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

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

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

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

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

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

五、靜態(tài)代理

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

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

//IPurchaseHouse: 抽象買(mǎi)房接口
interface IPurchaseHouse {
    void inquiryPrice();//詢(xún)價(jià)

    void visitHouse();//看房

    void payDeposit();//付定金

    void signAgreement();//簽合同

    void payMoney();//付錢(qián)

    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同意買(mǎi)房者來(lái)看房子");
    }

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

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

    @Override
    public void payMoney() {
        System.out.println("買(mǎi)房者付錢(qián)給HouseOwner");
    }

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

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

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

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

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

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

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

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

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

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

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

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

Process finished with exit code 0

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

上述結(jié)論可能有點(diǎn)抽象,假如現(xiàn)在有個(gè)不一樣需求比如A房產(chǎn)中介,在看房之前首先得簽訂一個(gè)看房協(xié)議,但是這個(gè)協(xié)議只涉及購(gòu)買(mǎi)用戶(hù)與中介之間的協(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();//通過(guò)具體房東HouseOwner引用去調(diào)用inquiryPrice
    }

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

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

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

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

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

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

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

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

Process finished with exit code 0

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

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

//IPurchaseHouseKt: 抽象買(mǎi)房接口
interface IPurchaseHouseKt {
    fun inquiryPrice() //詢(xún)價(jià)

    fun visitHouse() //看房

    fun payDeposit() //付定金

    fun signAgreement() //簽合同

    fun payMoney() //付錢(qián)

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

    override fun visitHouse() {
        println("HouseOwner同意買(mǎi)房者來(lái)看房子")
    }

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

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

    override fun payMoney() {
        println("買(mǎi)房者付錢(qián)給HouseOwner")
    }

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

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

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

Process finished with exit code 0

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

//修改后的HouseAgentAKt
class HouseAgentAKt(houseOwnerAKt: IPurchaseHouseKt) : IPurchaseHouseKt by houseOwnerAKt {
    private val mHouseOwnerAKt = houseOwnerAKt
    var mIsSigned: Boolean = false
    override fun visitHouse() {//只需要重寫(xiě)visitHouse即可
        if (mIsSigned) {
            println("您已經(jīng)簽訂了看房協(xié)議,可以看房了")
            mHouseOwnerAKt.visitHouse()
        } else {
            println("很抱歉,您還沒(méi)簽訂了看房協(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同意買(mǎi)房者來(lái)看房子
HouseOwner收了買(mǎi)房者1W RMB定金
HouseOwner與買(mǎi)房者簽訂合同
買(mǎi)房者付錢(qián)給HouseOwner
買(mǎi)房者拿到房子

Process finished with exit code 0

3、揭開(kāi)Kotlin中使用by代理語(yǔ)法糖衣

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

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

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

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

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

//DynamicProxy類(lèi)
class DynamicProxy implements InvocationHandler {
    private Object object;//被代理類(lèi)的引用

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(object, args);
    }
}
//Client類(lèi)
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è)代理中介,需要傳入被代理類(lèi)的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同意買(mǎi)房者來(lái)看房子
HouseOwner收了買(mǎi)房者1W RMB定金
HouseOwner與買(mǎi)房者簽訂合同
買(mǎi)房者付錢(qián)給HouseOwner
買(mǎi)房者拿到房子

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)非常精簡(jiǎn)了,所以在Kotlin在動(dòng)態(tài)代理實(shí)現(xiàn)并沒(méi)有特別不一樣的,它和Java的實(shí)現(xiàn)沒(méi)有不同。所以這里就不再重復(fù)實(shí)現(xiàn),只是換了Kotlin語(yǔ)言實(shí)現(xiàn)沒(méi)有什么不一樣的。

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

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

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

2、源碼分析論證

1、第一步我們先從Proxy.newProxyInstance方法進(jìn)入探究,通過(guò)它在外部更為直觀是可以獲取代理類(lèi)對(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í)際被代理類(lèi)的類(lèi)加載器實(shí)例。

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

h(InvocationHandler): 代理攔截器接口,一般需要使用子類(lèi)去實(shí)現(xiàn)該接口或匿名類(lèi)去實(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è)新的代理類(lèi)需要權(quán)限
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
         //注意點(diǎn)1: getProxyClass0方法拿到代理類(lèi)的Class對(duì)象實(shí)例cl
         //注意傳入的參數(shù)就是從外部傳入的loader(被代理類(lèi)的類(lèi)加載器)、intfs(被代理類(lèi)實(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í)例后,就通過(guò)反射機(jī)制創(chuàng)建代理類(lèi)實(shí)例
            final Constructor<);//先拿到代理類(lèi)的構(gòu)造器Constructor實(shí)例cons
            final InvocationHandler ih = h;
            //檢查代理類(lèi)構(gòu)造器是否是公有的public權(quán)限, 不是就會(huì)通過(guò)AccessController去修改訪問(wèn)權(quán)限以致于可以創(chuàng)建代理類(lèi)實(shí)例
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        cons.setAccessible(true);//將訪問(wèn)權(quán)限設(shè)置為可訪問(wèn)的
                        return null;
                    }
                });
            }
            //注意點(diǎn)3: 拿到構(gòu)造器實(shí)例cons后,就到了最為關(guān)鍵的也就是最后一步,創(chuàng)建代理類(lèi)實(shí)例。
            //但是需要注意的是構(gòu)造器反射傳入的參數(shù)是h,也就是傳入的InvocationHandler的實(shí)例,也可以進(jìn)一步推論生成的代理類(lèi)中存在以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);
        }
    }

再一次來(lái)梳理下newProxyInstance源碼流程:

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

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

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

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

    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)注意上面那段英文注釋: 如果給定的類(lèi)加載器中定義的代理類(lèi)實(shí)現(xiàn)了給定的接口,
        //那么就會(huì)直接返回緩存中的副本,否則它將通過(guò)ProxyClassFactory創(chuàng)建代理類(lèi)
        //注意點(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ǔ)的值。此類(lèi)用于緩存(key, sub-key) -> value鍵值對(duì)。內(nèi)部具體實(shí)現(xiàn)是借助了ConcurentMap>>,Supplier是一個(gè)接口,就一個(gè)get方法用于獲得值,不過(guò)是泛型V的包裝類(lèi),第一個(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)過(guò)一定計(jì)算得到泛型R的值。在WeakCache類(lèi)中存在兩個(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類(lèi)中只有一個(gè)核心get方法,里面包含了整個(gè)緩存的邏輯,注意我們獲取代理類(lèi)Class對(duì)象,就是通過(guò)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) {
        ...
        //通過(guò)傳入一級(jí)map的key,通過(guò)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)存在原來(lái)的oldValuesMap直接用它
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

 //------注意點(diǎn)1: subKeyFactory.apply(key, parameter)-----
        //根據(jù)傳入的一級(jí)map的key和參數(shù)parameter,通過(guò)subKeyFactory中的apply方法獲得sub-key,
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        //然后通過(guò)我們的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;
                }
            }
            //如果緩存中沒(méi)有supplier對(duì)象
            //或者supplier中g(shù)et返回是null
            //或者Factory對(duì)象沒(méi)有在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)存在的值,沒(méi)有直接返回null
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                 //如果拿到supplier為null,supplier就變?yōu)榱薴actory,這就是前面說(shuō)supplier為一個(gè)factory   
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    supplier = factory;
                } else {
                    //通過(guò)valuesMap.get()拿到supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

我們來(lái)一起梳理下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, 通過(guò)這個(gè)key拿到cacheKey,從而拿到對(duì)應(yīng)的valuesMap二級(jí)map。

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

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

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

注意點(diǎn)1----->獲取subKey過(guò)程: 通過(guò)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的過(guò)程:

我們都知道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ì)通過(guò)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,
            //這就是為什么前面說(shuō)過(guò)valuesMap中取出的Supplier可能是Factory可能是CacheValue,有沒(méi)有種偷梁換柱的趕腳
            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;
        }

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

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

    private static final class ProxyClassFactory
        implements BiFunction

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

6、第六步進(jìn)入ProxyGenerator中的generateProxyClass方法進(jìn)行探究,主要通過(guò)它來(lái)生成代理類(lèi)Class文件。generateProxyClass方法傳入的參數(shù)主要有: proxyName(唯一代理類(lèi)名稱(chēng)), interfaces(需要代理的接口Class數(shù)組), accessFlags(訪問(wèn)權(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----在生成的代理類(lèi)中加入Object類(lèi)幾個(gè)默認(rèn)方法比如常見(jiàn)的hashCode、equal、toString方法
        this.addProxyMethod(hashCodeMethod, Object.class);
        this.addProxyMethod(equalsMethod, Object.class);
        this.addProxyMethod(toStringMethod, Object.class);
        //取出代理類(lèi)的接口的Class數(shù)組
        Class[] var1 = this.interfaces;
        int var2 = var1.length;

        int var3;
        Class var4;
        //----注意點(diǎn)2---遍歷代理類(lèi)的接口的Class數(shù)組,將代理類(lèi)接口中的方法加入生成的代理類(lèi)中
        for(var3 = 0; var3 < var2; ++var3) {
            var4 = var1[var3];
            //獲得每個(gè)接口中定義的所有方法Method對(duì)象
            Method[] var5 = var4.getMethods();
            int var6 = var5.length;
            //然后再遍歷所有的Method對(duì)象,并把它加入到生成的代理類(lèi)中
            for(int var7 = 0; var7 < var6; ++var7) {
                Method var8 = var5[var7];
                this.addProxyMethod(var8, var4);
            }
        }
        ...
        try {
        //----注意點(diǎn)3 生成的代理類(lèi)中加入生成構(gòu)造器方法generateConstructor----
            this.methods.add(this.generateConstructor());
            var11 = this.proxyMethods.values().iterator();
            ...
       //----注意點(diǎn)4 生成的代理類(lèi)中加入生成靜態(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();
                //往輸出流寫(xiě)入生成代理類(lèi)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();
                //往輸出流寫(xiě)入生成代理類(lèi)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://systransis.cn/yun/7050.html

相關(guān)文章

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

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

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

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

0條評(píng)論

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