版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 員工培訓(xùn)體檢衛(wèi)生制度
- 小學(xué)衛(wèi)生教育培訓(xùn)制度
- 衛(wèi)生急救培訓(xùn)演練制度
- 學(xué)校衛(wèi)生工具領(lǐng)用制度
- 衛(wèi)生許可九個(gè)制度
- 溫泉洗浴衛(wèi)生制度
- 轄區(qū)單位衛(wèi)生檢查制度
- 衛(wèi)生檢查評(píng)比獎(jiǎng)勵(lì)制度
- 學(xué)生寢室衛(wèi)生制度
- 醫(yī)院健康教育衛(wèi)生制度
- 浙江省杭州市拱墅區(qū)2024-2025學(xué)年四年級(jí)上冊(cè)期末考試數(shù)學(xué)試卷(含答案)
- 光伏發(fā)電安裝質(zhì)量驗(yàn)收評(píng)定表
- AQ 1046-2007 地勘時(shí)期煤層瓦斯含量測(cè)定方法(正式版)
- 房屋過戶給子女的協(xié)議書的范文
- 超聲振動(dòng)珩磨裝置的總體設(shè)計(jì)
- 新媒體藝術(shù)的發(fā)展歷程及藝術(shù)特征
- 醫(yī)保違規(guī)行為分類培訓(xùn)課件
- 講課學(xué)生數(shù)學(xué)學(xué)習(xí)成就
- 醫(yī)療器械法規(guī)對(duì)互聯(lián)網(wǎng)銷售的限制
- 系桿拱橋系桿預(yù)應(yīng)力施工控制要點(diǎn)
- 三亞市海棠灣椰子洲島土地價(jià)格咨詢報(bào)告樣本及三洲工程造價(jià)咨詢有限公司管理制度
評(píng)論
0/150
提交評(píng)論