动态代理[JDK]机制解析
2017-12-06 23:46
113 查看
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
动态代理是一种比较常用的代理方式,也许你已经很熟悉它的使用了,但是它的实现原理你是否搞懂?不得不说搞懂动态代理的机制是很有必要的。为什么?当前十分火爆的Retrofit你应该很熟悉,没错,Retrofit就使用了动态代理。这么牛逼的框架都在使用的技术,你还不来学学它的原理么。
注意:JDK动态代理要求被代理类必须实现接口,而且对于private方法JDK动态代理也是无能无力的。当然,你会说那还玩毛线,直接用CGLIB不就行了,没错,CGLIB直接支持类,但是很遗憾,CGLIB不能再Android中使用,Android虚拟机还是与JVM有不同之处 的。
动态代理的特点是编译阶段没有代理类在运行时才生成代理类。
以下分析基于JDK1.7
示例下载(包含生成的代理类字节码文件,可以反编译查看):http://download.csdn.net/download/json_it/10148805
动态代理使用:
----> 你可以在这里做一些其他的工作=====
doSomething()
可以看到,代码量并不是很大。而且看起来也不是很复杂。说实话,以前初次接触动态代理的时候,我还是很疑惑的。这简短的几行代码背后到底发生了什么?动态代理给开发者带来了哪些惊喜呢?
ClassLoader:被代理类的类加载器;
Class<?> interfaces:被代理类实现的接口数组;
InvocationHandler:与被代理类关联的handler;
那么,这个proxyClassCache是一个什么东西呢?
查看缓存中是否存在 --> 如果存在,则直接返回supplier,get()-->如果不存在,则先生成Supplier(Factory是Supplier的子类),然后通过get()方法返回代理类。
现在最关键的就是这个get方法:
value = Objects.requireNonNull(valueFactory.apply(key, parameter));这个valueFactory是什么?就是ProxyClassFactory。
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
由此,我们找到了最终JDK是通过ProxyGenerator的generateProxyClass方法产生了最终的字节码。我们也可以利用这个类的方法将字节码保存到本地,然后反编译看一下代理类庐山真面目。
动态代理是一种比较常用的代理方式,也许你已经很熟悉它的使用了,但是它的实现原理你是否搞懂?不得不说搞懂动态代理的机制是很有必要的。为什么?当前十分火爆的Retrofit你应该很熟悉,没错,Retrofit就使用了动态代理。这么牛逼的框架都在使用的技术,你还不来学学它的原理么。
注意:JDK动态代理要求被代理类必须实现接口,而且对于private方法JDK动态代理也是无能无力的。当然,你会说那还玩毛线,直接用CGLIB不就行了,没错,CGLIB直接支持类,但是很遗憾,CGLIB不能再Android中使用,Android虚拟机还是与JVM有不同之处 的。
动态代理的特点是编译阶段没有代理类在运行时才生成代理类。
以下分析基于JDK1.7
示例下载(包含生成的代理类字节码文件,可以反编译查看):http://download.csdn.net/download/json_it/10148805
1、使用示例
定义接口:public interface ITestDynamicProxy { void doSomething(); }实现类:
public class TestDynamicProxy implements ITestDynamicProxy { @Override public void doSomething() { System.out.println("doSomething()"); } }自定义InvocationHandler:
public class MyInvoxationHandler implements InvocationHandler { private Object proxied; public MyInvoxationHandler(Object proxied) { this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("你可以在这里做一些其他的工作====="); return method.invoke(proxied, args); } }
动态代理使用:
public class MyDynamicProxy { public static void main(String[] args) { TestDynamicProxy testDynamicProxy = new TestDynamicProxy(); ITestDynamicProxy proxy = (ITestDynamicProxy) Proxy.newProxyInstance( ITestDynamicProxy.class.getClassLoader(), new Class[] { ITestDynamicProxy.class }, new MyInvoxationHandler(testDynamicProxy)); proxy.doSomething(); } }
----> 你可以在这里做一些其他的工作=====
doSomething()
可以看到,代码量并不是很大。而且看起来也不是很复杂。说实话,以前初次接触动态代理的时候,我还是很疑惑的。这简短的几行代码背后到底发生了什么?动态代理给开发者带来了哪些惊喜呢?
2、原理分析
Proxy.newProxyInstance(...)是动态代理的入口,它为我们生成了代理类:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)该方法有三个参数:
ClassLoader:被代理类的类加载器;
Class<?> interfaces:被代理类实现的接口数组;
InvocationHandler:与被代理类关联的handler;
@CallerSensitive可以看到,比较关键的方法是getProxyClass0(..)方法、
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
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 {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return newInstance(cons
d140
, 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 | 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());
}
}
}
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); }在这个方法中,我们发现其使用了缓存,通过loader和interfaces来获取代理类。有了缓存,我们很自然的就会想到,如果缓存中存在,则直接使用。否则,生成新的代理类。关于如何缓存,不再介绍。我们只需抓住关键思想,毕竟缓存不是我们分析的重点。
那么,这个proxyClassCache是一个什么东西呢?
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());它的两个参数让我们想到,第一个应该是用于产生Key的工厂,而第二个则是用于生成代理Class的工厂。
public V get(K key, P parameter) { Objects.requireNonNull(parameter); expungeStaleEntries(); Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap == null) { ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap != null) { valuesMap = oldValuesMap; } } // create subKey and retrieve the possible Supplier<V> stored by that // subKey from valuesMap Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; while (true) { if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance V value = supplier.get();//关键方法 if (value != null) { return value; } } // else no supplier in cache // or a supplier that returned null (could be a cleared CacheValue // or a Factory that wasn't successful in installing the CacheValue) // lazily construct a Factory if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } if (supplier == null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { // successfully installed Factory supplier = factory; } // else retry with winning supplier } else { if (valuesMap.replace(subKey, supplier, factory)) { // successfully replaced // cleared CacheEntry / unsuccessful Factory // with our Factory supplier = factory; } else { // retry with current supplier supplier = valuesMap.get(subKey); } } } }这段代码的主要思想是这样的:
查看缓存中是否存在 --> 如果存在,则直接返回supplier,get()-->如果不存在,则先生成Supplier(Factory是Supplier的子类),然后通过get()方法返回代理类。
现在最关键的就是这个get方法:
@Override public synchronized V get() { // serialize access // re-check Supplier<V> supplier = valuesMap.get(subKey); if (supplier != this) { // something changed while we were waiting: // might be that we were replaced by a CacheValue // or were removed because of failure -> // return null to signal WeakCache.get() to retry // the loop return null; } // else still us (supplier == this) // create new value V value = null; try { value = Objects.requireNonNull(valueFactory.apply(key, parameter)); } finally { if (value == null) { // remove us on failure valuesMap.remove(subKey, this); } } // the only path to reach here is with non-null value assert value != null; // wrap value with CacheValue (WeakReference) CacheValue<V> cacheValue = new CacheValue<>(value); // try replacing us with CacheValue (this should always succeed) if (valuesMap.replace(subKey, this, cacheValue)) { // put also in reverseMap reverseMap.put(cacheValue, Boolean.TRUE); } else { throw new AssertionError("Should not reach here"); } // successfully replaced us with new CacheValue -> return the value // wrapped by it return value; } }我们终于发现了最关键的信息:
value = Objects.requireNonNull(valueFactory.apply(key, parameter));这个valueFactory是什么?就是ProxyClassFactory。
@Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); 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. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { 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) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces); try { return 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()); } } }关键信息:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
由此,我们找到了最终JDK是通过ProxyGenerator的generateProxyClass方法产生了最终的字节码。我们也可以利用这个类的方法将字节码保存到本地,然后反编译看一下代理类庐山真面目。
public class MyDynamicProxy { public static void main(String[] args) { TestDynamicProxy testDynamicProxy = new TestDynamicProxy(); ITestDynamicProxy proxy = (ITestDynamicProxy) Proxy.newProxyInstance( ITestDynamicProxy.class.getClassLoader(), new Class[] { ITestDynamicProxy.class }, new MyInvoxationHandler(testDynamicProxy)); proxy.doSomething(); createProxyClassFile(); } private static void createProxyClassFile() { String name = "ProxySubject"; byte[] data = ProxyGenerator.generateProxyClass(name, new Class[] { ITestDynamicProxy.class }); FileOutputStream out = null; try { out = new FileOutputStream(name + ".class"); System.out.println((new File("hello")).getAbsolutePath()); out.write(data); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (null != out) try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } }找到我们生成的ProxySubject.class,反编译看下:
import com.example.proxy.ITestDynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class ProxySubject extends Proxy implements ITestDynamicProxy { private static Method m1; private static Method m0; private static Method m3; private static Method m2; public ProxySubject(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); } public final boolean equals(Object paramObject) throws { 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 int hashCode() throws { 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 void doSomething() throws { try { this.h.invoke(this, m3, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() throws { 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") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m3 = Class.forName("com.example.proxy.ITestDynamicProxy").getMethod("doSomething", 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()); } } }代理类是proxy的子类,实现了代理接口。除了生成常用的几个通用的方法外,还生成了代理接口方法:
public final void doSomething() throws { try { this.h.invoke(this, m3, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } }可以看到对代理类的代理接口的调用会被转发为由InvocationHandler这个接口的 invoke(对方法的增强就写在这里面) 方法来进行调用。这也是为什么需要我们来实现InvocationHandler,并在其invoke方法中完成主要工作的原因了。
相关文章推荐
- Java动态代理机制原理详解(JDK 和CGLIB,Javassist,ASM)
- JDK的动态代理深入解析(Proxy,InvocationHandler)
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
- Java JDK动态代理解析
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
- Java 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
- Android插件化原理解析——Hook机制之动态代理
- JDK动态代理源码解析
- java JDK动态代理的机制
- Hadoop源码解析之java动态代理机制
- JAVA动态代理机制解析
- jdk动态代理(动态生成字节码与反射机制的结合)
- 深度剖析JDK动态代理机制
- JDK 动态代理对异常的处理及InvocationTargetException异常解析
- 深入理解JDK动态代理机制
- JDK的动态代理深入解析(Proxy,InvocationHandler)
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
- JDK的动态代理机制
- Android插件化原理解析——Hook机制之动态代理
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)