01、动态代理--JDK动态代理
一、概述
- JDK动态代理只适用于,被代理的类实现了一个或多个接口
- JDK动态代理产生的代理类,会实现被代理类实现的所有接口(代理类和被代理类是兄弟关系)
- JDK动态代理主要涉及java.lang.reflect包中的两个类:Proxy 和 InvocationHandler
- 动态代理(JDK动态代理和CGLib动态代理)是实现AOP的绝好底层技术
二、实例
package com.offer.note.Java基础.动态代理.JDK动态代理; public interface Browser { void visitInternet(); }
package com.offer.note.Java基础.动态代理.JDK动态代理; /** * 被代理类 * * @author: xueguanfeng * @date: 2018-05-15 09:57 */ public class ChromeBrowser implements Browser { /** * 被代理类的目标方法 */ @Override public void visitInternet() { System.out.println("visit YouTube"); } }
package com.offer.note.Java基础.动态代理.JDK动态代理; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 这是调度处理器接口的实现,注意:这不是动态代理类,动态代理类是由它依赖的Proxy类产生的 * 主要关注两点: * 1、Proxy类是如何产生目标类的代理类的 * 2、invoke方法是被谁调用的,在什么时候被调用的 * * @author: xueguanfeng * @date: 2018-05-15 09:58 */ public class JdkBrowserProxy implements InvocationHandler { /** * 关联被代理对象 */ private Browser browser; public JdkBrowserProxy(Browser browser) { this.browser = browser; } /** * 动态产生代理对象 * @return */ public Browser getProxy() { /** * Proxy.newProxyInstance()方法的三个参数分别是: * 1、类加载器 * 2、被代理类实现的接口 * 3、InvocationHandler的实例 * * 由Proxy类的newProxyInstance方法动态产生的代理类,会按统一顺序准确的实现其创建时指定的接口, 即browser.getClass().getInterfaces() */ Browser b = (Browser) Proxy.newProxyInstance(browser.getClass().getClassLoader(), browser.getClass().getInterfaces(), this); return b; } /** * 此方法会被动态代理类调用 * @param proxy 动态生成的代理类的实例 * @param method 被代理类的目标方法的Method实例 * @param args 被代理类的目标方法的入参 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { encrypt(); //增强 Object retVal = method.invoke(browser, args); decrypt(); //增强 return retVal; } ///////////////////增强////////////////////////////////////// /** * 加密 */ private void encrypt() { System.out.println("encrypt ..."); } /** * 解密 */ private void decrypt() { System.out.println("decrypt ..."); } }
package com.offer.note.Java基础.动态代理.JDK动态代理; /** * 测试类 * * @author: xueguanfeng * @date: 2018-05-15 10:00 */ public class JdkDynamicProxyTest { public static void main(String[] args) { Browser browser = new JdkBrowserProxy(new ChromeBrowser()).getProxy(); /** * 动态生成的代理类继承了Proxy类--$Proxy0 * Proxy类聚合了InvocationHandler的实例,故$Proxy0能调用invoke方法 * InvocationHandler的实例聚合了被代理类的实例,故invoke方法中可以调用被代理类的目标方法 */ //这里执行的是动态生成的代理类的visitInternet方法,而不是被代理类的目标方法 browser.visitInternet(); } }
三、源码解析
1、动态代理对象的产生
Browser b = (Browser) Proxy.newProxyInstance(browser.getClass().getClassLoader(), browser.getClass().getInterfaces(), this);
2、查看Proxy类的newProxyInstance方法
阅读newProxyInstance方法的源码,主要关注一下三点:
-
Class<?> cl = getProxyClass0(loader, intfs); //查找或生成代理的Class对象
-
final Constructor<?> cons = cl.getConstructor(constructorParams); //获取构造器
-
return cons.newInstance(new Object[]{h}); //通过构造器,利用反射生成代理类实例
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); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ 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); } }
/** * Generate a proxy class. Must call the checkProxyAccess method * to perform permission checks before calling this. */ private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory return proxyClassCache.get(loader, interfaces); }
3、获取ChromeBrowser被代理类对应的动态代理类的源码
public static void getDynamicProxyCode() { String path = "D://DynamicProxyCode.class"; byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", ChromeBrowser.class.getInterfaces()); FileOutputStream out = null; try { out = new FileOutputStream(path); out.write(classFile); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } }
4、动态代理类的源码
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // import com.offer.note.Java基础.动态代理.JDK动态代理.Browser; 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 Browser { private static Method m1; private static Method m2; private static Method m3; 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 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 void visitInternet() throws { try { super.h.invoke(this, m3, (Object[])null); //调用InvocationHandler实例的invoke方法 } 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")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("com.offer.note.Java基础.动态代理.JDK动态代理.Browser").getMethod("visitInternet"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
说明:由动态产生的代理类的源码可以看出,当调用代理类的所代理的方法中(即上图红色标注的visitInternet()方法),会调用InvocationHandler实例中的invoke()方法,然后再在invoke()方法中调用代理类的目标方法。