java动态代理原理及解析
轉(zhuǎn)載自?http://blog.csdn.net/scplove/article/details/52451899
代理:設(shè)計(jì)模式
代理模式是一種常用的設(shè)計(jì)模式,其目的就是為其他對(duì)象提供一個(gè)代理以控制對(duì)某個(gè)真實(shí)對(duì)象的訪問(wèn)。代理類(lèi)負(fù)責(zé)為委托類(lèi)預(yù)處理消息,過(guò)濾消息并轉(zhuǎn)發(fā)消息,以及進(jìn)行消息被委托類(lèi)執(zhí)行后的后續(xù)處理。
通過(guò)代理層這一中間層,有效的控制對(duì)于真實(shí)委托類(lèi)對(duì)象的直接訪問(wèn),同時(shí)可以實(shí)現(xiàn)自定義的控制策略(Spring的AOP機(jī)制),設(shè)計(jì)上獲得更大的靈活性。
java動(dòng)態(tài)代理的類(lèi)和接口(jdk1.6源碼)
1,java.lang.reflect.Proxy:動(dòng)態(tài)代理機(jī)制的主類(lèi),提供一組靜態(tài)方法為一組接口動(dòng)態(tài)的生成對(duì)象和代理類(lèi)。
// 方法 1: 該方法用于獲取指定代理對(duì)象所關(guān)聯(lián)的調(diào)用處理器 public static InvocationHandler getInvocationHandler(Object proxy) // 方法 2:該方法用于獲取關(guān)聯(lián)于指定類(lèi)裝載器和一組接口的動(dòng)態(tài)代理類(lèi)的類(lèi)對(duì)象 public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)// 方法 3:該方法用于判斷指定類(lèi)對(duì)象是否是一個(gè)動(dòng)態(tài)代理類(lèi) public static boolean isProxyClass(Class<?> cl) // 方法 4:該方法用于為指定類(lèi)裝載器、一組接口及調(diào)用處理器生成動(dòng)態(tài)代理類(lèi)實(shí)例 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
2,java.lang.reflect.InvocationHandler:調(diào)用處理器接口,自定義invokle方法,用于實(shí)現(xiàn)對(duì)于真正委托類(lèi)的代理訪問(wèn)。
/**該方法負(fù)責(zé)集中處理動(dòng)態(tài)代理類(lèi)上的所有方法調(diào)用。第一個(gè)參數(shù)既是代理類(lèi)實(shí)例,第二個(gè)參數(shù)是被調(diào)用的方法對(duì)象第三個(gè)方法是調(diào)用參數(shù)。調(diào)用處理器根據(jù)這三個(gè)參數(shù)進(jìn)行預(yù)處理或分派到委托類(lèi)實(shí)例上發(fā)射執(zhí)行 */ public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
3,java.lang.ClassLoader:類(lèi)裝載器類(lèi),將類(lèi)的字節(jié)碼裝載到 Java 虛擬機(jī)(JVM)中并為其定義類(lèi)對(duì)象,然后該類(lèi)才能被使用。Proxy類(lèi)與普通類(lèi)的唯一區(qū)別就是其字節(jié)碼是由 JVM 在運(yùn)行時(shí)動(dòng)態(tài)生成的而非預(yù)存在于任何一個(gè) .class 文件中。?
每次生成動(dòng)態(tài)代理類(lèi)對(duì)象時(shí)都需要指定一個(gè)類(lèi)裝載器對(duì)象:newProxyInstance()方法第一個(gè)參數(shù)
動(dòng)態(tài)代理機(jī)制
java動(dòng)態(tài)代理創(chuàng)建對(duì)象的過(guò)程為如下步驟:?
1,通過(guò)實(shí)現(xiàn) InvocationHandler 接口創(chuàng)建自己的調(diào)用處理器;
- 1
- 2
- 3
2,通過(guò)為 Proxy 類(lèi)指定 ClassLoader 對(duì)象和一組 interface 來(lái)創(chuàng)建動(dòng)態(tài)代理類(lèi);
// 通過(guò) Proxy 為包括 Interface 接口在內(nèi)的一組接口動(dòng)態(tài)創(chuàng)建代理類(lèi)的類(lèi)對(duì)象 Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... });- 1
- 2
3,通過(guò)反射機(jī)制獲得動(dòng)態(tài)代理類(lèi)的構(gòu)造函數(shù),其唯一參數(shù)類(lèi)型是調(diào)用處理器接口類(lèi)型;
// 通過(guò)反射從生成的類(lèi)對(duì)象獲得構(gòu)造函數(shù)對(duì)象 Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class });- 1
- 2
4,通過(guò)構(gòu)造函數(shù)創(chuàng)建動(dòng)態(tài)代理類(lèi)實(shí)例,構(gòu)造時(shí)調(diào)用處理器對(duì)象作為參數(shù)被傳入。
// 通過(guò)構(gòu)造函數(shù)對(duì)象創(chuàng)建動(dòng)態(tài)代理類(lèi)實(shí)例 Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });- 1
- 2
為了簡(jiǎn)化對(duì)象創(chuàng)建過(guò)程,Proxy類(lèi)中的newProxyInstance方法封裝了2~4,只需兩步即可完成代理對(duì)象的創(chuàng)建。
// InvocationHandlerImpl 實(shí)現(xiàn)了 InvocationHandler 接口,并能實(shí)現(xiàn)方法調(diào)用從代理類(lèi)到委托類(lèi)的分派轉(zhuǎn)發(fā) InvocationHandler handler = new InvocationHandlerImpl(..); // 通過(guò) Proxy 直接創(chuàng)建動(dòng)態(tài)代理類(lèi)實(shí)例 Interface proxy = (Interface)Proxy.newProxyInstance( classLoader, new Class[] { Interface.class }, handler );- 1
- 2
- 3
- 4
- 5
- 6
- 7
動(dòng)態(tài)代理的注意點(diǎn):?
1,包:代理接口是public,則代理類(lèi)被定義在頂層包(package為空),否則(default),代理類(lèi)被定義在該接口所在包,
2,生成的代理類(lèi)為public final,不能被繼承,
3,類(lèi)名:格式是“$ProxyN”,N是逐一遞增的數(shù)字,代表Proxy被第N次動(dòng)態(tài)生成的代理類(lèi),要注意,對(duì)于同一組接口(接口的排列順序也相同),不會(huì)重復(fù)創(chuàng)建動(dòng)態(tài)代理類(lèi),而是返回一個(gè)先前已經(jīng)創(chuàng)建并緩存了的代理類(lèi)對(duì)象。提高了效率。
4,類(lèi)繼承關(guān)系:
?
Proxy 類(lèi)是它的父類(lèi),這個(gè)規(guī)則適用于所有由 Proxy 創(chuàng)建的動(dòng)態(tài)代理類(lèi)。(也算是java動(dòng)態(tài)代理的一處缺陷,java不支持多繼承,所以無(wú)法實(shí)現(xiàn)對(duì)class的動(dòng)態(tài)代理,只能對(duì)于Interface的代理)而且該類(lèi)還實(shí)現(xiàn)了其所代理的一組接口,這就是為什么它能夠被安全地類(lèi)型轉(zhuǎn)換到其所代理的某接口的根本原因。
5,代理類(lèi)的根類(lèi) java.lang.Object 中有三個(gè)方法也同樣會(huì)被分派到調(diào)用處理器的 invoke 方法執(zhí)行,它們是 hashCode,equals 和 toString,?
代碼在反編譯中?
一個(gè)動(dòng)態(tài)代理的demo
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class HelloServiceProxy implements InvocationHandler { private Object target; /** * 綁定委托對(duì)象并返回一個(gè)【代理占位】 * @param target 真實(shí)對(duì)象 * @return 代理對(duì)象【占位】 */ public Object bind(Object target, Class[] interfaces) { this.target = target; //取得代理對(duì)象 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);} @Override /** * 同過(guò)代理對(duì)象調(diào)用方法首先進(jìn)入這個(gè)方法. * @param proxy --代理對(duì)象 * @param method -- 方法,被調(diào)用方法. * @param args -- 方法的參數(shù) */ public Object invoke(Object proxy , Method method, Object[] args) throws Throwable { System.err.println("############我是JDK動(dòng)態(tài)代理################"); Object result = null; //反射方法前調(diào)用 System.err.println("我準(zhǔn)備說(shuō)hello。"); //反射執(zhí)行方法 相當(dāng)于調(diào)用target.sayHelllo; result=method.invoke(target, args); //反射方法后調(diào)用. System.err.println("我說(shuō)過(guò)hello了"); return result; } }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
其中,bind方法中的newProxyInstanc方法,就是生成一個(gè)代理對(duì)象,第一個(gè)參數(shù)是類(lèi)加載器,第二個(gè)參數(shù)是真實(shí)委托對(duì)象所實(shí)現(xiàn)的的接口(代理對(duì)象掛在那個(gè)接口下),第三個(gè)參數(shù)this代表當(dāng)前HelloServiceProxy類(lèi),換句話說(shuō)是使用HelloServiceProxy作為對(duì)象的代理。
invoke方法有三個(gè)參數(shù):第一個(gè)proxy是代理對(duì)象,第二個(gè)是當(dāng)前調(diào)用那個(gè)方法,第三個(gè)是方法的參數(shù)。
public class ProxyTest { public static void main(String[] args) { HelloServiceProxy proxy = new HelloServiceProxy(); HelloService service = new HelloServiceImpl(); //綁定代理對(duì)象。 service = (HelloService) proxy.bind(service, new Class[] {HelloService.class}); //這里service經(jīng)過(guò)綁定,就會(huì)進(jìn)入invoke方法里面了。 service.sayHello("張三"); } }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
測(cè)試結(jié)果:
############我是JDK動(dòng)態(tài)代理################ 我準(zhǔn)備說(shuō)hello。 hello 張三 我說(shuō)過(guò)hello了- 1
- 2
- 3
- 4
源碼跟蹤
Proxy 類(lèi)
// 映射表:用于維護(hù)類(lèi)裝載器對(duì)象到其對(duì)應(yīng)的代理類(lèi)緩存 private static Map loaderToCache = new WeakHashMap(); // 標(biāo)記:用于標(biāo)記一個(gè)動(dòng)態(tài)代理類(lèi)正在被創(chuàng)建中 private static Object pendingGenerationMarker = new Object(); // 同步表:記錄已經(jīng)被創(chuàng)建的動(dòng)態(tài)代理類(lèi)類(lèi)型,主要被方法 isProxyClass 進(jìn)行相關(guān)的判斷 private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap()); // 關(guān)聯(lián)的調(diào)用處理器引用 protected InvocationHandler h;- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
Proxy 靜態(tài)方法 newProxyInstance
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { // 檢查 h 不為空,否則拋異常if (h == null) { throw new NullPointerException(); } // 獲得與制定類(lèi)裝載器和一組接口相關(guān)的代理類(lèi)類(lèi)型對(duì)象/** Look up or generate the designated proxy class.*/Class<?> cl = getProxyClass0(loader, interfaces); // 通過(guò)反射獲取構(gòu)造函數(shù)對(duì)象并生成代理類(lèi)實(shí)例/** Invoke its constructor with the designated invocation handler.*/try {final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = h;SecurityManager sm = System.getSecurityManager();if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {// create proxy instance with doPrivilege as the proxy class may// implement non-public interfaces that requires a special permissionreturn AccessController.doPrivileged(new PrivilegedAction<Object>() {public Object run() {return newInstance(cons, ih);}});} else {return newInstance(cons, ih);}} catch (NoSuchMethodException e) {throw new InternalError(e.toString());} }private static Object newInstance(Constructor<?> cons, InvocationHandler h) {try {return cons.newInstance(new Object[] {h} );} catch (IllegalAccessException e) {throw new InternalError(e.toString());} catch (InstantiationException e) {throw new InternalError(e.toString());} catch (InvocationTargetException e) {Throwable t = e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString());}}}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
動(dòng)態(tài)代理真正的關(guān)鍵是在?getProxyClass0?方法,
getProxyClass0方法分析
方法分為四個(gè)步驟:?
1,對(duì)這組接口進(jìn)行一定程度的安全檢查?
檢查接口類(lèi)對(duì)象是否對(duì)類(lèi)裝載器可見(jiàn)并且與類(lèi)裝載器所能識(shí)別的接口類(lèi)對(duì)象是完全相同的,還會(huì)檢查確保是 interface 類(lèi)型而不是 class 類(lèi)型。
2,從 loaderToCache 映射表中獲取以類(lèi)裝載器對(duì)象為關(guān)鍵字所對(duì)應(yīng)的緩存表,如果不存在就創(chuàng)建一個(gè)新的緩存表并更新到 loaderToCache。?
loaderToCache存放鍵值對(duì)(接口名字列表,動(dòng)態(tài)生成的代理類(lèi)的類(lèi)對(duì)象引用)。當(dāng)代理類(lèi)正在被創(chuàng)建時(shí)它會(huì)臨時(shí)保存(接口名字列表,pendingGenerationMarker)。標(biāo)記 pendingGenerationMarke 的作用是通知后續(xù)的同類(lèi)請(qǐng)求(接口數(shù)組相同且組內(nèi)接口排列順序也相同)代理類(lèi)正在被創(chuàng)建,請(qǐng)保持等待直至創(chuàng)建完成。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
3,動(dòng)態(tài)創(chuàng)建代理類(lèi)的class對(duì)象
/*** Choose a name for the proxy class to generate.*/long num;synchronized (nextUniqueNumberLock) {num = nextUniqueNumber++;}String proxyName = proxyPkg + proxyClassNamePrefix + num;/** Verify that the class loader hasn't already* defined a class with the chosen name.*/// 動(dòng)態(tài)地生成代理類(lèi)的字節(jié)碼數(shù)組byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);try {// 動(dòng)態(tài)地定義新生成的代理類(lèi)proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);} catch (ClassFormatError e) {/** A ClassFormatError here means that (barring bugs in the* proxy class generation code) there was some other* invalid aspect of the arguments supplied to the proxy* class creation (such as virtual machine limitations* exceeded).*/throw new IllegalArgumentException(e.toString());}// 把生成的代理類(lèi)的類(lèi)對(duì)象記錄進(jìn) proxyClasses 表proxyClasses.put(proxyClass, null);- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
首先根據(jù)規(guī)則(接口public與否),生成代理類(lèi)的名稱(chēng),$ProxyN格式,然后動(dòng)態(tài)生成代理類(lèi)。?
所有的代碼生成的工作都由 ProxyGenerator 所完成了,該類(lèi)在rt.jar中,需要反編譯
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
4,代碼生成過(guò)程進(jìn)入結(jié)尾部分,根據(jù)結(jié)果更新緩存表,如果成功則將代理類(lèi)的類(lèi)對(duì)象引用更新進(jìn)緩存表,否則清楚緩存表中對(duì)應(yīng)關(guān)鍵值,最后喚醒所有可能的正在等待的線程。
finally {/** We must clean up the "pending generation" state of the proxy* class cache entry somehow. If a proxy class was successfully* generated, store it in the cache (with a weak reference);* otherwise, remove the reserved entry. In all cases, notify* all waiters on reserved entries in this cache.*/synchronized (cache) {if (proxyClass != null) {cache.put(key, new WeakReference(proxyClass));} else {cache.remove(key);}cache.notifyAll();}} return proxyClass;- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
InvocationHandler解析
代碼參考:http://rejoy.iteye.com/blog/1627405?
通過(guò)getProxyClass0方法中生成具體的class文件的過(guò)程,定義path,講class文件寫(xiě)到指定的磁盤(pán)中,反編譯生成的代理class文件。?
發(fā)現(xiàn)在靜態(tài)代碼塊中獲取了的方法有:Object中的equals方法、Object中的hashCode方法、Object中toString方法 ,?以及invoke的接口方法。
后語(yǔ)
至此,JDK是動(dòng)態(tài)生成代理類(lèi),并通過(guò)調(diào)用解析器,執(zhí)行接口實(shí)現(xiàn)的方法的原理已經(jīng)一目了然。動(dòng)態(tài)代理加上反射,是很多框架的基礎(chǔ)。比如Spring的AOP機(jī)制,自定義前置后置通知等控制策略,以及mybatis中的運(yùn)用反射和動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)插件技術(shù)等等。
文章參考:?
http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html?
http://blog.csdn.net/ykzhen2015/article/details/50312651
總結(jié)
以上是生活随笔為你收集整理的java动态代理原理及解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java动态代理与反射详解
- 下一篇: java中三种常见内存溢出错误的处理方法