Java 代理模式實現(xiàn)方式,主要有如下五種方法
靜態(tài)代理,工程師編輯代理類代碼,實現(xiàn)代理模式;在編譯期就生成了代理類。
基于 JDK 實現(xiàn)動態(tài)代理,通過jdk提供的工具方法Proxy.newProxyInstance動態(tài)構(gòu)建全新的代理類(繼承Proxy類,并持有InvocationHandler接口引用 )字節(jié)碼文件并實例化對象返回。(jdk動態(tài)代理是由java內(nèi)部的反射機制來實例化代理對象,并代理的調(diào)用委托類方法)
基于CGlib 動態(tài)代理模式 基于繼承被代理類生成代理子類,不用實現(xiàn)接口。只需要被代理類是非final 類即可。(cglib動態(tài)代理底層是借助asm字節(jié)碼技術(shù)
基于 Aspectj 實現(xiàn)動態(tài)代理(修改目標類的字節(jié),織入代理的字節(jié),在程序編譯的時候 插入動態(tài)代理的字節(jié)碼,不會生成全新的Class )
基于 instrumentation 實現(xiàn)動態(tài)代理(修改目標類的字節(jié)碼、類裝載的時候動態(tài)攔截去修改,基于javaagent)-javaagent:spring-instrument-4.3.8.RELEASE.jar(類裝載的時候 插入動態(tài)代理的字節(jié)碼,不會生成全新的Class )
靜態(tài)代理實現(xiàn)步驟:
委托類和代理類之間的約束接口Cat
約束接口實現(xiàn)類 Lion,實現(xiàn) Cat 接口,委托角色
代理類實現(xiàn) FeederProxy,實現(xiàn)Cat 接口,并含有一個 Cat接口引用屬性。 代理角色,代理 cat接口屬性引用實例的行為并可以新增公共邏輯。
基于 JDK 實現(xiàn)動態(tài)代理:java的java.lang.reflect包下提供了Proxy類和一個 InvocationHandler 接口,這個類Proxy定義了生成JDK動態(tài)代理類的方法getProxyClass(ClassLoader loader,Class<?>... interfaces)生成動態(tài)代理類,返回class實例代表一個class文件??梢员4嬖?class 文件查看jdk生成的代理類文件長什么樣。該生成的動態(tài)代理類繼承Proxy類,(重要特性) ,并實現(xiàn)公共接口。InvocationHandler這個接口 是被動態(tài)代理類回調(diào)的接口,我們所有需要增加的針對委托類的統(tǒng)一處理邏輯都增加到invoke 方法里面在調(diào)用委托類接口方法之前或之后 結(jié)束戰(zhàn)斗。
①創(chuàng)建一個與代理類相關(guān)聯(lián)的InvocationHandler,并將代理類引用傳遞進去,Proxy.newProxyInstance的方式創(chuàng)建代理類。
②創(chuàng)建 InvocationHandler 實例并設(shè)置代理的目標類對象,通過 proxyClass 獲得 一個帶有InvocationHandler參數(shù)的構(gòu)造器constructor,通過構(gòu)造器創(chuàng)建一個 動態(tài)代理類實例。ProxyConstructor.newInstance
一個典型的基于JDK動態(tài)代理創(chuàng)建對象過程可分為以下四個步驟:
1、通過實現(xiàn)InvocationHandler接口創(chuàng)建自己的調(diào)用處理器 IvocationHandler handler = new InvocationHandlerImpl(...);
2、通過為Proxy類指定ClassLoader對象和一組interface代理類需要實現(xiàn)的接口,創(chuàng)建動態(tài)代理類類文件,默認JDK并不會保存這個文件到文件中;可以保存起來觀察生成的代理類結(jié)構(gòu)Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通過上面新建的代理clazz的反射機制獲取動態(tài)代理類的一個構(gòu)造函數(shù),其構(gòu)造函數(shù)入?yún)㈩愋褪钦{(diào)用處理器接口(IvocationHandler)類型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通過構(gòu)造函數(shù)實例創(chuàng)建代理類實例,此時需將調(diào)用處理器對象作為參數(shù)被傳入 Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler)); 為了簡化對象創(chuàng)建過程,Proxy類中的newInstance工具方法封裝了2~4,只需兩步即可完成代理對象的創(chuàng)建。
基于CGlib 技術(shù)動態(tài)代理代理類實現(xiàn) (基于繼承)
Cglib是針對類來實現(xiàn)代理的,他的原理是對代理的目標類生成一個子類,并覆蓋其中方法實現(xiàn)增強,因為底層是基于創(chuàng)建被代理類的一個子類,所以它避免了JDK動態(tài)代理類的缺陷。
但因為采用的是繼承,所以不能對final修飾的類進行代理。final修飾的類不可繼承。
創(chuàng)建Enhancer加強器,用來創(chuàng)建動態(tài)代理類,同時需要設(shè)置方法攔截器回調(diào)引用,對于代理類上所有方法的調(diào)用,都會調(diào)用CallBack,而Callback則需要實現(xiàn)intercept() 方法進行攔截,enhancer.create()創(chuàng)建實例。
Cglib 總結(jié)
CGlib可以傳入接口也可以傳入普通的類,接口使用實現(xiàn)的方式,普通類使用會使用繼承的方式生成代理類.
由于是繼承方式,如果是 static方法,private方法,final方法等描述的方法是不能被代理的
做了方法訪問優(yōu)化,使用建立方法索引的方式避免了傳統(tǒng)JDK動態(tài)代理需要通過Method方法反射調(diào)用.
提供callback 和filter設(shè)計,可以靈活地給不同的方法綁定不同的callback。編碼更方便靈活。
CGLIB會默認代理Object中equals,toString,hashCode,clone等方法。比JDK代理多了clone。
太好了!總算有人把動態(tài)代理、CGlib、AOP都說清楚了! - 云+社區(qū) - 騰訊云 (tencent.com)