摘要:用戶在調用被動態代理過的對象的方法時,調用的請求會被自動發給代理對象實現了接口的方法,由方法來實現對請求的統一處理。動態代理實現切面代替該語句塊一定會在前面執行。
用戶在調用被動態代理過的對象的方法時,調用的請求會被自動發給代理對象(實現了InvocationHandler接口)的invoke()方法,由invoke()方法來實現對請求的統一處理。
源碼分析Java.lang.reflect.Proxy
public class Proxy implements java.io.Serializable { private static final Class>[] constructorParams = { InvocationHandler.class }; private static final WeakCache[], Class>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); ...... @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class>[] intfs = interfaces.clone(); //淺克隆 final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } //生成代理類的class Class> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } //getConstructor(InvocationHandler.class) 獲取代理類的構造器 final Constructor> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction () { public Void run() { cons.setAccessible(true); return null; } }); } //代理類實例化返回 return cons.newInstance(new Object[]{h}); } ...... } private static Class> getProxyClass0(ClassLoader loader, Class>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // key為WeakReference,若緩存中存在相同key,則返回ProxyClass,若不存在,則用ProxyClassFactory創建ProxyClass。 return proxyClassCache.get(loader, interfaces); //java.lang.reflect.WeakCache 這個內核分析? } ...... }
private static final class ProxyClassFactory implements BiFunction$Proxy.class[], Class>> { //?所有代理類ProxyClass名字的前綴? private static final String proxyClassNamePrefix = "$Proxy"; // 用計數器生成代理類ProxyClass的名字 private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class> apply(ClassLoader loader, Class>[] interfaces) { Map , Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); //對每一個interface Class進行驗證 for (Class> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. * 用IdentityHashMap來驗證interface Class的唯一性,因為IdentityHashMap的key比較是==,即比較內存地址。 */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; int accessFlags = Modifier.PUBLIC | Modifier.FINAL; // 對于非公共接口,ProxyClass的包名設置為接口的包名?? for (Class> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { accessFlags = Modifier.FINAL; String name = intf.getName(); int n = name.lastIndexOf("."); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) { throw new IllegalArgumentException( "non-public interfaces from different packages"); } } } //?對于公共接口,ProxyClass的包名為com.sun.proxy?? if (proxyPkg == null) { proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } long num = nextUniqueNumber.getAndIncrement(); //ProxyClass的完全限定名 String proxyName = proxyPkg + proxyClassNamePrefix + num; //由c++寫的ProxyGenerator生成代理類的二進制字節碼 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { //?根據二進制字節碼返回相應的ProxyClass?? return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); } } }
以下是反編譯$Proxy0.class:
public?final?class?$Proxy0?extends?Proxy?implements?MyInterface1{?? ??private?static?Method?m1;?? ??private?static?Method?m3;?? ??private?static?Method?m0;?? ??private?static?Method?m2;?? ? ??public?$Proxy0(InvocationHandler?paramInvocationHandler)?{?? ????super(paramInvocationHandler);?? ??}?? ?? ??public?final?boolean?equals(Object?paramObject)?{?? ????try?{?? ??????return?((Boolean)this.h.invoke(this,?m1,?new?Object[]?{?paramObject?})).booleanValue();?? ????}?? ????catch?(Error|RuntimeException?localError)?{?? ??????throw?localError;?? ????}?? ????catch?(Throwable?localThrowable)?{?? ??????throw?new?UndeclaredThrowableException(localThrowable);?? ????}?? ??}?? ?? ??public?final?void?sayHello(String?paramString)?{?? ????try?{?? ??????this.h.invoke(this,?m3,?new?Object[]?{?paramString?});?? ??????return;?? ????}?? ????catch?(Error|RuntimeException?localError)?{?? ??????throw?localError;?? ????}?? ???catch?(Throwable?localThrowable)?{?? ??????throw?new?UndeclaredThrowableException(localThrowable);?? ????}?? ??}?? ?? ??public?final?int?hashCode()?{?? ????try?{?? ??????return?((Integer)this.h.invoke(this,?m0,?null)).intValue();?? ????}?? ????catch?(Error|RuntimeException?localError)?{?? ??????throw?localError;?? ????}?? ????catch?(Throwable?localThrowable)?{?? ??????throw?new?UndeclaredThrowableException(localThrowable);?? ????}?? ??}?? ?? ??public?final?String?toString()?{?? ????try?{?? ???? return?(String)this.h.invoke(this,?m2,?null);?? ????}?? ????catch?(Error|RuntimeException?localError)?{?? ??????throw?localError;?? ????}?? ????catch?(Throwable?localThrowable)?{?? ??????throw?new?UndeclaredThrowableException(localThrowable);?? ????}?? ??}?? ?? ??static?{?? ????try?{?? ??????m1?=?Class.forName("java.lang.Object").getMethod("equals",?new?Class[]?{?Class.forName("java.lang.Object")?});?? ??????m3?=?Class.forName("com.mikan.proxy.MyInterface1").getMethod("sayHello",?new?Class[]?{?Class.forName("java.lang.String")?});?? ??????m0?=?Class.forName("java.lang.Object").getMethod("hashCode",?new?Class[0]);?? ????m2?=?Class.forName("java.lang.Object").getMethod("toString",?new?Class[0]);?? ??????return;?? ????}?? ????catch?(NoSuchMethodException?localNoSuchMethodException)?{?? ??????throw?new?NoSuchMethodError(localNoSuchMethodException.getMessage());????}?? ????catch?(ClassNotFoundException?localClassNotFoundException)?{?? ??????throw?new?NoClassDefFoundError(localClassNotFoundException.getMessage());?? ????}?? ??}?? }?
?
$Proxy0.class的總結:
對于要代理沒有接口的類,則必須繼承該沒有接口的類,從而覆蓋其方法,但由于java不能多繼承,這里代理類已經繼承了Proxy類了,不能再繼承其他的類,所以JDK的動態代理不支持對實現類的代理,只支持接口的代理。
構造方法的入參為InvocationHandler,這說明該代理類是實現了InvocationHandler接口的類的代理類,而InvocationHandler實現類再代理真正的實體類。
靜態代碼塊會初始化真正實體類的Method對象,以及Object類的equals、hashCode、toString的Method對象。
總結:
Proxy 會從內部類WeakCache中根據ClassLoader 和interfaces獲取ProxyClass(若緩存中存在相同key,則返回ProxyClass,若不存在,則用ProxyClassFactory創建ProxyClass(由ProxyGenerator生成二進制碼,再將寫成*.class文件))。
切面InvocationHandler:
public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{?? ????//?BeforeAdvice?? ????Object?retVal?=?null;?? ????try?{?? ????????retVal?=?method.invoke(target,?args);??//?AroundAdvice?代替該語句????? ????????//?AfterReturningAdvice?? ????}?? ????catch?(Throwable?e)?{?? ????????//?AfterThrowingAdvice?? ????}?? ????finally?{?? ???? //finally塊一定會在return前面執行。 ????????//?AfterAdvice?? ????}?? ????return?retVal;?? }??
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67267.html
摘要:要明白,動態代理類的存在意義是為了攔截方法并修改邏輯而動態代理的局限性之一就是只能攔截接口所聲明的方法。因為動態代理類是繼承自業務類,所以該類和方法不能聲明成無法繼承或重寫。者最終都是生成了一個新的動態代理類對象。 動態代理 1、先談靜態代理 對于靜態代理,我們已經很熟悉了。我們擁有一個抽象類,真實類繼承自抽象類并重寫其業務方法,代理類持有真實類的對象實例,在重寫業務方法中通過調用真實...
摘要:動態代理的核心是接口和類。以上結果說明它生成的代理類為,說明是代理。測試前提實現接口測試類使用接口方式注入代理方式必須以接口方式注入測試配置為,運行結果如下實際校驗邏輯。。。。 本文也同步發布至簡書,地址:https://www.jianshu.com/p/f70... AOP設計模式通常運用在日志,校驗等業務場景,本文將簡單介紹基于Spring的AOP代理模式的運用。 1. 代理模...
摘要:與靜態代理對比,動態代理是在動態生成代理類,由代理類完成對具體方法的封裝,實現的功能。本文將分析中兩種動態代理的實現方式,和,比較它們的異同。那如何動態編譯呢你可以使用,這是一個封裝了的庫,幫助你方便地實現動態編譯源代碼。 發現Java面試很喜歡問Spring AOP怎么實現的之類的問題,所以寫一篇文章來整理一下。關于AOP和代理模式的概念這里并不做贅述,而是直奔主題,即AOP的實現方...
摘要:值得一提的是由于采用動態創建子類的方式生成代理對象,所以不能對目標類中的方法進行代理。動態代理中生成的代理類是子類,調試的時候可以看到,打開源碼可看到實現了和也就實現方法。 前面講到了動態代理的底層原理,接下來我們來看一下aop的動態代理.Spring AOP使用了兩種代理機制:一種是基于JDK的動態代理,一種是基于CGLib的動態代理. ①JDK動態代理:使用JDK創建代理有一個限制...
閱讀 3393·2021-09-22 15:01
閱讀 524·2019-08-30 11:11
閱讀 950·2019-08-29 16:17
閱讀 1209·2019-08-29 12:23
閱讀 2023·2019-08-26 11:48
閱讀 3176·2019-08-26 11:48
閱讀 1415·2019-08-26 10:33
閱讀 1927·2019-08-26 10:30