Java 動(dòng)態(tài)代理你真的懂了嗎(動(dòng)態(tài)和代理)_第1頁
Java 動(dòng)態(tài)代理你真的懂了嗎(動(dòng)態(tài)和代理)_第2頁
Java 動(dòng)態(tài)代理你真的懂了嗎(動(dòng)態(tài)和代理)_第3頁
Java 動(dòng)態(tài)代理你真的懂了嗎(動(dòng)態(tài)和代理)_第4頁
Java 動(dòng)態(tài)代理你真的懂了嗎(動(dòng)態(tài)和代理)_第5頁
已閱讀5頁,還剩8頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第Java動(dòng)態(tài)代理你真的懂了嗎(動(dòng)態(tài)和代理)好幾天不寫文章,今天來寫一篇,從之前的計(jì)劃表上看到還有關(guān)于java的動(dòng)態(tài)代理沒寫,這個(gè)技術(shù)平常用的少,也不是特別好理解,今天補(bǔ)上這篇,希望能講明白,不至于像我一樣迷茫好久,開始吧

動(dòng)態(tài)代理分兩部分,動(dòng)態(tài)和代理,我們先說下代理模式

1、代理模式

代理模式是常用的設(shè)計(jì)模式之一,也是開發(fā)中常見的設(shè)計(jì)模式。

簡(jiǎn)單的描述一下,代理模式就是將實(shí)現(xiàn)類隔離開,比如你想給你女朋友過個(gè)生日,找個(gè)明星唱生日歌,你女朋友的偶像是周杰倫,想找周杰倫給她過生日,唱歌,但是你不太能聯(lián)系上周杰倫,即使在社交網(wǎng)站上聯(lián)系,可能也不太理你,所以你可以聯(lián)系周杰倫的經(jīng)紀(jì)人進(jìn)行溝通,經(jīng)紀(jì)人就是周杰倫的代理。

實(shí)現(xiàn)過程:

定義一個(gè)唱歌的接口,代表業(yè)務(wù)

publicinterfaceISing{

voidsing();

}

周杰倫有唱歌的業(yè)務(wù),并且業(yè)務(wù)突出,實(shí)現(xiàn)接口

*周杰倫

publicclassJayImpimplementsISing{

@Override

publicvoidsing(){

System.out.println("sayhappybirthdaytoyougirlfriend");

}

經(jīng)紀(jì)人接受業(yè)務(wù),經(jīng)紀(jì)人的構(gòu)造函數(shù)需要和明星綁定

經(jīng)紀(jì)人接收唱歌的業(yè)務(wù),今天可能是周杰倫唱,明天可能經(jīng)紀(jì)人換了明星,比如蔡依林也是可以的

*經(jīng)紀(jì)人

publicclassJayProxyimplementsISing{

ISingtarget;

*初始化的時(shí)候,和明星進(jìn)行簽約

*@paramtarget

publicJayProxy(ISingtarget){

this.target=target;

@Override

publicvoidsing(){

target.sing();

}

聯(lián)系經(jīng)紀(jì)人進(jìn)行唱歌,周杰倫唱完歌之后,經(jīng)紀(jì)人收錢,veryhappy

publicclassMoneyOwner{

publicstaticvoidmain(String[]args){

JayImpjay=newJayImp();

//周杰倫和經(jīng)紀(jì)人進(jìn)行簽約,這一步可以放在內(nèi)部實(shí)現(xiàn)

JayProxyjayProxy=newJayProxy(jay);

jayProxy.sing();

}

看下執(zhí)行結(jié)果,皆大歡喜,你女朋友很開心。

上面這一套就是代理模式的實(shí)現(xiàn),

但是代理類只能代理一種類,如果為每一個(gè)服務(wù)都創(chuàng)建一個(gè)代理類,有點(diǎn)傻

而且接口如果改變的情況下代理類也需要改變,非常不方便,周杰倫又是拍電影,做綜藝,寫歌,業(yè)務(wù)很多

好了,靜態(tài)代理該說的也說了,相信看到這里你應(yīng)該沒有什么不理解的,下面我們正式開始今天的正餐,動(dòng)態(tài)代理

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

動(dòng)態(tài)代理是Java提供的一種代理方式,這個(gè)技術(shù)的核心點(diǎn)就是在運(yùn)行期的時(shí)候?qū)涌谶M(jìn)行增強(qiáng),生成class對(duì)象,然后加載進(jìn)虛擬機(jī),說簡(jiǎn)單點(diǎn)就是虛擬機(jī)幫你創(chuàng)建了一個(gè)實(shí)現(xiàn)你接口的class

廢話少說,先來實(shí)現(xiàn)一個(gè)動(dòng)態(tài)代理

第一步定義接口,上面代碼已經(jīng)有了ISing就不重復(fù)定義了

第二步實(shí)現(xiàn)接口,上面代碼也已經(jīng)實(shí)現(xiàn)了JayImp,也不重復(fù)定義了,這次經(jīng)紀(jì)人多簽約了一個(gè)歌手,林俊杰,看下實(shí)現(xiàn)

packageorg.pdool.dynamic;

*林俊杰

publicclassJJImpimplementsISing{

@Override

publicvoidsing(){

System.out.println("IamJJ!happybirthdaytoyou");

}

第三步,經(jīng)紀(jì)人可以動(dòng)態(tài)派出簽約歌手,注意經(jīng)紀(jì)人要實(shí)現(xiàn)InvocationHandler,這樣才能統(tǒng)一處理所有的方法調(diào)用

importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Method;

importjava.lang.reflect.Proxy;

publicclassJayAgentFactoryimplementsInvocationHandler{

Objecttarget;

publicJayAgentFactory(Objecttarget){

this.target=target;

//生成代理類

publicISingCreatProxyedObj(){

return(ISing)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);

@Override

publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{

Objectinvoke=method.invoke(target,args);

logAfter(invoke);

returninvoke;

publicvoidlogAfter(Objectinvoke){

System.out.println("結(jié)果"+invoke);

System.out.println("收入++");

}

第四步,接收業(yè)務(wù)

packageorg.pdool.dynamic;

importjava.lang.reflect.Proxy;

publicclassAain{

publicstaticvoidmain(String[]args){

JayImpjayImp=newJayImp();

ISingsubjectProxy=(ISing)Proxy.newProxyInstance(jayImp.getClass().getClassLoader(),jayImp.getClass().getInterfaces(),newJayAgentFactory(jayImp));

subjectProxy.sing();

}

總結(jié):動(dòng)態(tài)代理是Java提供的實(shí)現(xiàn)方式,需要InvocationHandler的實(shí)現(xiàn)類

1、為什么編輯器可以提示接口的方法?因?yàn)閺?qiáng)轉(zhuǎn)編輯器才會(huì)能有提示

2、生成的內(nèi)存class是的默認(rèn)構(gòu)造函數(shù)是需要InvocationHandler參數(shù)

3、創(chuàng)建代理class的核心參數(shù)是類加載器,接口,還有InvocationHandler子類。

類加載器保證和目標(biāo)類在同一個(gè)加載器內(nèi),可以調(diào)用,防止不同加載器加載的類之間不能調(diào)用

接口就是你要代理的接口

InvocationHandler子類是轉(zhuǎn)發(fā)器,將所有的消息進(jìn)行攔截處理轉(zhuǎn)發(fā)

3、原理研究

實(shí)現(xiàn)看到了,探究下原理,動(dòng)態(tài)代理的最根本的在于根據(jù)接口創(chuàng)建內(nèi)存class,這一步是怎么實(shí)現(xiàn)的,我們跟著源碼瞧一瞧

1、克隆接口里函數(shù)的信息

2、查找或生成指定的代理類,如果緩存中有,則用緩存的,沒有則創(chuàng)建

3、通過反射,拿到代理類的構(gòu)造函數(shù)

4、通過構(gòu)造函數(shù)創(chuàng)建一個(gè)代理對(duì)象,并關(guān)聯(lián)InvocationHandler的對(duì)象

/**parametertypesofaproxyclassconstructor*/

privatestaticfinalClass[]constructorParams=

{InvocationHandler.class};

看到了流程,我們看下代理class到底是什么樣子的,

importsun.misc.ProxyGenerator;

publicclassTest{

publicstaticvoidmain(String[]args){

//開啟保存代碼class屬性

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

ProxyGenerator.generateProxyClass("Xiangcai",JayImp.class.getInterfaces());

}

執(zhí)行上面的函數(shù),可以看到在項(xiàng)目的路徑下生成Xiangcai.class

接著看看xiangcai.class到底有哪些東西,直接拖到編輯器就可以了

importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Method;

importjava.lang.reflect.Proxy;

importjava.lang.reflect.UndeclaredThrowableException;

importorg.pdool.dynamic.ISing;

publicfinalclassxiangcaiextendsProxyimplementsISing{

privatestaticMethodm1;

privatestaticMethodm2;

privatestaticMethodm3;

privatestaticMethodm0;

publicxiangcai(InvocationHandlervar1)throws{

super(var1);

publicfinalbooleanequals(Objectvar1)throws{

try{

return(Boolean)super.h.invoke(this,m1,newObject[]{var1});

}catch(RuntimeException|Errorvar3){

throwvar3;

}catch(Throwablevar4){

thrownewUndeclaredThrowableException(var4);

publicfinalStringtoString()throws{

try{

return(String)super.h.invoke(this,m2,(Object[])null);

}catch(RuntimeException|Errorvar2){

throwvar2;

}catch(Throwablevar3){

thrownewUndeclaredThrowableException(var3);

//注意看這里!?。∑渌亩疾恢匾?/p>

publicfinalvoidsing()throws{

try{

super.h.invoke(this,m3,(Object[])null);

}catch(RuntimeException|Errorvar2){

throwvar2;

}catch(Throwablevar3){

thrownewUndeclaredThrowableException(var3);

publicfinalinthashCode()throws{

try{

return(Integer)super.h.invoke(this,m0,(Object[])null);

}catch(RuntimeException|Errorvar2){

throwvar2;

}catch(Throwablevar3){

thrownewUndeclaredThrowableException(var3);

static{

try{

m1=Class.forName("java.lang.Object").getMethod("equals",Class.forName("java.lang.Object"));

m2=Class.forName("java.lang.Object").getMethod("toString");

m3=Class.forName("org.pdool.dynamic.ISing").getMethod("sing");

m0=Class.forName("java.lang.Object").getMethod("hashCode");

}catch(NoSuchMethodExceptionvar2){

thrownewNoSuchMethodError(var2.getMessage());

}catch(ClassNotFoundExceptionvar3){

thrownewNoClassDefFoundError(var3.getMessage());

}

可以看到實(shí)現(xiàn)了sing的接口,并且調(diào)用了invokehandler的方法invoke.好了,真相大白了,你明白了嗎?

有人會(huì)說,道理我都懂,可是不會(huì)用啊,但是沒看到好的應(yīng)用場(chǎng)景,所以有段時(shí)間是沒掌握這些的,下面我們就具體一下應(yīng)用場(chǎng)景

在切面編程(AOP)中,需要攔截特定的方法,通常,會(huì)選擇動(dòng)態(tài)代理方式??磦€(gè)具體的例子spring-data-jpa的實(shí)現(xiàn)

具體的使用:

spring中訪問數(shù)據(jù)庫的使用

importcom.tao.springboot.hibernate.entity.Customer;

importorg.springframework.data.jpa.repository.JpaRepository;

publicinterfaceCustomerRepositoryextendsJpaRepositoryCustomer,Long{

}

只要實(shí)現(xiàn)上面的接口就可以直接操作數(shù)據(jù)庫,是不是很簡(jiǎn)單?

有幾個(gè)問題,你稍微思考下:

1、兩個(gè)泛型什么意思?

2、數(shù)據(jù)庫連接在哪?是怎么注入的?

3、只實(shí)現(xiàn)接口是怎么操作數(shù)據(jù)庫的?

第一個(gè)問題答案:

Customer為表對(duì)象對(duì)應(yīng)的entity實(shí)體。

Long是表的主鍵類型,

第二個(gè)答案:

數(shù)據(jù)庫連接是在spring啟動(dòng)的時(shí)候自動(dòng)注入到spring容器中的,在JpaRepository的實(shí)現(xiàn)類自動(dòng)注入的

第三個(gè)答案:

所有的的接口在spring啟動(dòng)的時(shí)候會(huì)生成代理類,目標(biāo)類target就是實(shí)現(xiàn)類SimpleJpaRepository

看下類圖

看下JpaRepository的定義,都是一些常用方法

publicinterfaceJpaRepositoryT,IDextendsPagingAndSortingRepositoryT,ID,QueryByExampleExecutorT{

ListTfindAll();

ListTfindAll(Sortvar1);

ListTfindAllById(IterableIDvar1);

SextendsTListSsaveAll(IterableSvar1);

voidflush();

SextendsTSsaveAndFlush(Svar1);

voiddeleteInBatch(IterableTvar1);

voiddeleteAllInBatch();

TgetOne(IDvar1);

SextendsTListSfindAll(ExampleSvar1);

SextendsTListSfindAll(ExampleSvar1,Sortvar2);

}

看下SimpleJpaRepository的定義:

publicclassSimpleJpaRepositoryT,IDimplementsJpaRepositoryImplementationT,ID{

privatestaticfinalStringID_MUST_NOT_BE_NULL="Thegivenidmustnotbenull!";

privatefinalJpaE

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論