我需要了解的动态代理
2018-02-25 00:46
183 查看
一.说明
动态代理的思想是:代理模式+反射。静态代理,代理者的代码是由程序员自己或者通过一些自动化工具生成,然后再进行编译。
动态代理则正好相反,通过反射机制动态的生成代理对象。
代理模式可参考下面的文章链接:
http://blog.csdn.net/a910626/article/details/50760980
反射可参考下面的文章链接:
http://blog.csdn.net/a910626/article/details/51111918
动态代理涉及的相关类:
动态代理主要的Java 类有java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler,下面是动态代理的UML类图。
java.lang.reflect.Proxy它提供了一组静态方法来为一组接口生成代理类和对象。
// 根据一组接口和类加载器来生成代理类的Class对象 public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces) // 用来获取该代理类对象所关联的处理器 public static InvocationHandler getInvocationHandler(Object proxy) // 用来判断是否是代理类 public static boolean isProxyClass(Class<?> cl) //生成代理对象 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
二.源码分析
Java的动态代理通过调用Proxy.newProxyInstance()方法生成代理对象。这个方法通过传入的三个参数类加载器、接口数组、调用处理器来生成动态代理对象。public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, interfaces); /* * Invoke its constructor with the designated invocation handler. */ try { final Constructor<?> cons = cl.getConstructor(constructorParams); return newInstance(cons, h); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } }
1.getProxyClass0(loader, interfaces);
这个方法有些长,抽取关键地方分析
1)先抽取被代理类实现的接口Interface,检测是否符合要求
/* collect interface names to use as key for proxy class cache */ String[] interfaceNames = new String[interfaces.length]; // for detecting duplicates Set<Class<?>> interfaceSet = new HashSet<>(); for (int i = 0; i < interfaces.length; i++) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ String interfaceName = interfaces[i].getName(); Class<?> interfaceClass = null; try { interfaceClass = Class.forName(interfaceName, false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != interfaces[i]) { throw new IllegalArgumentException( interfaces[i] + " 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. */ if (interfaceSet.contains(interfaceClass)) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } interfaceSet.add(interfaceClass); interfaceNames[i] = interfaceName; }
2)查看代理对象缓存中是否有我们要创建的代理类,如果有,直接获取;没有则创建
如果有则: return proxyClassCache.get(loader, interfaces);
没有则通过ProxyClassFactory创建。
这个类比较核心的方法如下:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
我猜大致意思就是全转为字节码,运行时(runtime)生成代理对象字节码。
2.cl.getConstructor(constructorParams);
根据上一步生成的代理类Class对象,来获取到构造器。
3.newInstance(cons, h);
创建代理实例,将
newInstance(cons, ih);//将InvocationHandler h传入代理对象中
说明:
怎么看生成的代理对象的源码是什么样的呢?
可参考链接:
查看JDK动态代理生成的类的内容
http://blog.csdn.net/zknxx/article/details/77919332
以下是Proxy0的源码
public final class $Proxy0 extends Proxy implements Manager { private static Method m1; private static Method m0; private static Method m3; private static Method m2; static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m3 = Class.forName("com.ml.test.Manager").getMethod("modify", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); } catch (NoSuchMethodException nosuchmethodexception) { throw new NoSuchMethodError(nosuchmethodexception.getMessage()); } catch (ClassNotFoundException classnotfoundexception) { throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } public $Proxy0(InvocationHandler invocationhandler) { super(invocationhandler); } @Override public final boolean equals(Object obj) { try { return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue(); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } @Override public final int hashCode() { try { return ((Integer) super.h.invoke(this, m0, null)).intValue(); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final void modify() { try { super.h.invoke(this, m3, null); return; } catch (Error e) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } @Override public final String toString() { try { return (String) super.h.invoke(this, m2, null); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } }
即生成的代理类的每个方法中都会调用InvocationHandler的invoke方法,并且会把方法名、代理对象、参数回调回去,我们可以在InvocationHandler的invoke方法中增加一些代码等效于在方法前后插入代码。
三.一个栗子
1.简单代理模式写法
public interface Subject { void request(); }
public class RealSubject implements Subject { @Override public void request() { System.out.println("---realsubject---"); } }
public class ProxySubject implements Subject { private RealSubject mRealSubject; public ProxySubject(RealSubject realSubject) { mRealSubject = realSubject; } @Override public void request() { mRealSubject.request(); } }
public class Client { public static void main(String[] args) { ProxySubject proxySubject = new ProxySubject(new RealSubject()); proxySubject.request(); } }
2.动态代理模式写法
public interface Subject { void request(); }
public class ProxyHandler implements InvocationHandler { private Subject mSubject; public ProxyHandler(Subject subject) { mSubject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.print("---before---"); Object result = method.invoke(mSubject, args); System.out.print("---end---"); return result; } }
public class RealSubject implements Subject { @Override public void request() { System.out.println("---realsubject---"); } }
public class Client { public static void main(String[] args) { // ProxySubject proxySubject = new ProxySubject(new RealSubject()); // proxySubject.request(); RealSubject realSubject = new RealSubject(); ProxyHandler handler = new ProxyHandler(realSubject); Subject proxyInstance = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), handler); proxyInstance.request(); } }
不过动态代理可以不用具体的实现类,直接代理接口类。
public class Client { public static void main(String[] args) { // ProxySubject proxySubject = new ProxySubject(new RealSubject()); // proxySubject.request(); // RealSubject realSubject = new RealSubject(); // ProxyHandler handler = new ProxyHandler(realSubject); // Subject proxyInstance = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), handler); // proxyInstance.request(); Subject subject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class<?>[] { Subject.class }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("dynamic Proxy"); return null; } } ); subject.request(); } }
这个动态代理的好处是你连RealSubject都不需要。
参考资料
Java 动态代理机制分析及扩展,第 1 部分https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html
动态代理解析
http://blog.csdn.net/kyosky110/article/details/51911463
java 动态代理深度学习(Proxy,InvocationHandler),含$Proxy0源码
http://lijingshou.iteye.com/blog/1949134
戏说代理模式和Java动态代理
https://www.jianshu.com/p/0d919e54eef0
相关文章推荐
- .Net动态代理Castle ( 了解创建动态代理 )
- jdk的动态代理及为什么需要接口
- Spring系列(2)--为什么需要动态代理
- Spring系列(2)--为什么需要动态代理
- nginx 域名代理动态解析,需要一些新的模块
- 教你清楚了解JAVA动态代理
- 自己编写动态代理机制代码,深入了解动态代理
- 基于JDK动态代理的深入了解
- Spring aop 基于JDK动态代理和CGLIB代理的原理以及为什么JDK代理需要基于接口
- Spring系列(2)--为什么需要动态代理
- 动态代理的深入了解
- Android注解学习之了解Java动态代理Proxy
- 动态代理(了解但不常用)
- 动态代理1 (JDK 需要实现接口)
- JAVA动态代理
- 你需要认真了解并对待的11条理财真理
- JDK动态代理实现分析
- java动态代理详解
- 深度学习——你需要了解的八大开源框架
- 理解动态代理的实现过程