JDK動態代理是代理模式的一種實現方式,其只能代理接口。java
一、 新建一個接口緩存
二、 爲接口建立一個實現類app
三、 建立代理類實現java.lang.reflect.InvocationHandler接口ide
四、 測試函數
根據使用步驟:工具
首先新建一個接口Subject源碼分析
package com.lnjecit.proxy; /** * Subject * 抽象主題接口 * @author * @create 2018-03-29 14:16 **/ public interface Subject { void doSomething(); }
而後爲接口RealSubject新建一個實現類RealSubject學習
/** * RealSubject * 真實主題類 * @author * @create 2018-03-29 14:21 **/ public class RealSubject implements Subject { @Override public void doSomething() { System.out.println("RealSubject do something"); } }
接着建立一個代理類JDKDynamicProxy實現java.lang.reflect.InvocationHandler接口,重寫invoke方法測試
package com.lnjecit.proxy.dynamic.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * JDKDynamicProxy * jdkd動態代理 * * @author * @create 2018-03-29 16:17 **/ public class JDKDynamicProxy implements InvocationHandler { private Object target; public JDKDynamicProxy(Object target) { this.target = target; } /** * 獲取被代理接口實例對象 * @param <T> * @return */ public <T> T getProxy() { return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Do something before"); Object result = method.invoke(target, args); System.out.println("Do something after"); return result; } }
新建測試類Client測試結果ui
package com.lnjecit.proxy; import com.lnjecit.proxy.dynamic.jdk.JDKDynamicProxy; /** * Client * client測試代碼 * * @author * @create 2018-03-29 14:26 **/ public class Client { public static void main(String[] args) { // 保存生成的代理類的字節碼文件 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); // jdk動態代理測試 Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy(); subject.doSomething(); } }
輸出結果:
Do something before
RealSubject do something
Do something after
因爲設置
sun.misc.ProxyGenerator.saveGeneratedFiles 的值爲true,因此代理類的字節碼內容保存在了項目根目錄下,文件名爲$Proxy0.class
這裏查看JDK1.8.0_65的源碼,經過debug學習JDK動態代理的實現原理
大概流程
一、爲接口建立代理類的字節碼文件
二、使用ClassLoader將字節碼文件加載到JVM
三、建立代理類實例對象,執行對象的目標方法
動態代理涉及到的主要類:
java.lang.reflect.Proxy
java.lang.reflect.InvocationHandler
java.lang.reflect.WeakCache
sun.misc.ProxyGenerator
首先看Proxy類中的newProxyInstance方法:
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { // 判斷InvocationHandler是否爲空,若爲空,拋出空指針異常 Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * 生成接口的代理類的字節碼文件 */ Class<?> cl = getProxyClass0(loader, intfs); /* * 使用自定義的InvocationHandler做爲參數,調用構造函數獲取代理類對象實例 */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
newProxyInstance方法調用getProxyClass0方法生成代理類的字節碼文件。
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { // 限定代理的接口不能超過65535個 if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // 若是緩存中已經存在相應接口的代理類,直接返回;不然,使用ProxyClassFactory建立代理類 return proxyClassCache.get(loader, interfaces); }
其中緩存使用的是WeakCache實現的,此處主要關注使用ProxyClassFactory建立代理的狀況。ProxyClassFactory是Proxy類的靜態內部類,實現了BiFunction接口,實現了BiFunction接口中的apply方法。
當WeakCache中沒有緩存相應接口的代理類,則會調用ProxyClassFactory類的apply方法來建立代理類。
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // 代理類前綴 private static final String proxyClassNamePrefix = "$Proxy"; // 生成代理類名稱的計數器 private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { /* * 校驗類加載器是否能經過接口名稱加載該類 */ 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"); } /* * 校驗該類是不是接口類型 */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * 校驗接口是否重複 */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // 代理類包名 int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * 非public接口,代理類的包名與接口的包名相同 */ 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"); } } } if (proxyPkg == null) { // public代理接口,使用com.sun.proxy包名 proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * 爲代理類生成名字 */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * 真正生成代理類的字節碼文件的地方 */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { // 使用類加載器將代理類的字節碼文件加載到JVM中 return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); } } }
,
在ProxyClassFactory類的apply方法中可看出真正生成代理類字節碼的地方是ProxyGenerator類中的generateProxyClass,該類未開源,可是可使用IDEA、或者反編譯工具jd-gui來查看。
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) { ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2); final byte[] var4 = var3.generateClassFile(); // 是否要將生成代理類的字節碼文件保存到磁盤中 if (saveGeneratedFiles) { // .... } return var4; }
在測試案例中,設置系統屬性sun.misc.ProxyGenerator.saveGeneratedFiles值爲true
// 保存生成的代理類的字節碼文件 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
打開$Proxy0.class文件以下:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.sun.proxy; import com.lnjecit.proxy.Subject; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Subject { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void doSomething() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("com.lnjecit.proxy.Subject").getMethod("doSomething"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
可看到
一、代理類繼承了Proxy類而且實現了要代理的接口,因爲java不支持多繼承,因此JDK動態代理不能代理類
二、重寫了equals、hashCode、toString
三、有一個靜態代碼塊,經過反射或者代理類的全部方法
四、經過invoke執行代理類中的目標方法doSomething
參考資料: