JDK动态代理 JDK动态代理允许在运行时通过反射创建Java接口的实现。代理可以被看作是一个将方法调用转发给目标实例并最终将目标实例产生的任何结果返回给调用方的主体。由于调用链将通过代理,代理本身也将能够在目标方法调用前后执行任意处理。非常流行的Spring框架使用JDK动态代理作为其代理创建策略之一。当我们在Spring服务中声明一个事务方法时,容器将创建一个代理,该代理将拦截对目标方法的调用,并用所需的事务管理指令来修饰它。
JDK动态代理是JDK附带的一个特性,由java.lang.reflect.* 包提供支持。它必须使用接口来提供代理对象。在JDK动态代理逻辑中,必须实现java.lang.reflect.InvocationHandler接口才能实现代理逻辑类。实现JDK动态代理需要几下几步:
创建接口
创建一个接口实现类的实例对象,这个实例对象就是目标对象
创建一个代理类,这个类必须实现java.lang.reflect.InvocationHandler接口
JDK动态代理相关类介绍 在Java的动态代理机制中,有两个重要的类和接口,一个是InvocationHandler(Interface),另一个是proxy(Class),这个类和接口必须用来实现动态代理。
InvocationHandler 每个动态代理类必须实现java.lang.reflect.InvocationHandler,每个代理类得是实例都与一个handler关联,当我们通过一个代理对象调用一个方法,对这个方法的调用被转发给InvocationHandler接口的invoke方法调用,然后在这个接口中通过反射调用这个方法。
1 2 3 4 public interface InvocationHandler { public Object invoke (Object proxy, Method method, Object[] args) throws Throwable ;}
这个接口有三个参数:
Proxy:指JDK动态生成的final修饰的代理对象
Method:指的是我们要调用目标对象的方法的方法对象
Args:指调用目标对象的方法的方法参数
Proxy 代理类的作用是动态创建代理对象类,最常用的方法是newProxyInstance
1 2 3 4 5 6 7 8 9 public class Proxy implements java .io .Serializable { @CallerSensitive public static Object newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { ... } }
newProxyInstance方法的三个参数分别如下:
Loader:一个类加载器对象,它定义了要为加载生成代理对象的类加载器。
Interfaces:一个接口对象数组,这意味着我们将为需要代理的对象提供一组接口,生成的代理对象实现这些接口。
InvocationHandler :一个InvocationHandler对象,它表示在动态代理对象调用方法时与哪个InvocationHandler对象关联。可以把它理解为一个拦截器,拦截方法的调用,在目标方法调用前后进行通知。
用JDK代理创建代理 动态代理类是一个类,它是在运行时生成的类。生成它时,必须向它提供一组接口。然后类公布这些接口的实现。你可以将类实例用作这些接口中的任何一个。当然,这个类是一个代理。它不会做实质性的工作。在生成他的实例时,必须提供一个handler来接管实际工作。
假设你要检查是否有权限调用目标对象的某个方法,如果授权失败,可以抛出一个运行时异常AuthorizationException(本例中只是简单打印信息)。接口授权具体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.wonglay;import java.lang.reflect.Method;public interface AuthorizationService { void authorize (Method method) ; }
假设有一个PersistenceServiceImpl类实现了PersistenceService接口,它有两个方法:save和load。现在需要检查是否有权限调用这两个方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.wonglay;public class PersistenceServiceImpl implements PersistenceService { @Override public void save (Long id, String data) { System.out.println(data + " has been saved successfully" ); } @Override public String load (Long id) { return "wonglay.com" ; } }
现在授权接口和需要授权的接口都有了,现在需要将这两个类关联起来,我们需要实现一个InvocationHandler接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package com.wonglay;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class PersistenceServiceInvocationHandler implements InvocationHandler { private final AuthorizationService authorizationService; private final Object target; public PersistenceServiceInvocationHandler (AuthorizationService authorizationService, Object target) { this .authorizationService = authorizationService; this .target = target; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { authorizationService.authorize(method); Object result = method.invoke(target, args); return result; } public Object getProxy () { return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this ); } }
生成的代理类会继承一个java.lang.reflect.Proxy类,java.lang.reflect.Proxy类声明了一个InvocationHandler变量,调用代理对象的方法时会委托给InvocationHandler(本例中就是PersistenceServiceInvocationHandler)的invoke,在invoke方法中通过反射调用目标方法,因此可以对方法进行增强。这几个类之间的关系如图3.1。
面是为PersistenceServicel类创建代理对象的过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.wonglay;public class Main { public static void main (String[] args) { PersistenceService persistenceService = new PersistenceServiceImpl(); AuthorizationService authorizationService = (method) -> { String methodName = method.getName(); System.out.println("[" + methodName + "] method authenticating..." ); }; PersistenceServiceInvocationHandler persistenceServiceInvocationHandler = new PersistenceServiceInvocationHandler(authorizationService, persistenceService); PersistenceService proxy = (PersistenceService) persistenceServiceInvocationHandler.getProxy(); System.out.println(proxy.load(1L )); } }
打印结果如图3.2
实现原理探究 上面只是简单介绍了一下创建代理的过程,接下来将分析具体JDK是如何生成代理类,以及生成的代理类是什么样子,我们可以加上一个JVM参数,将生成的代理类写到磁盘。
1 2 3 4 5 6 7 8 public class Main { public static void main (String[] args) { System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles" , "true" ); PersistenceService persistenceService = new PersistenceServiceImpl(); ..... }
生成的代理类如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 package com.sun.proxy;import com.wonglay.PersistenceService;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 PersistenceService { private static Method m1; private static Method m2; private static Method m4; 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}); } 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 save (Long var1, String var2) throws { try { super .h.invoke(this , m4, new Object[]{var1, var2}); } catch (RuntimeException | Error var4) { throw var4; } catch (Throwable var5) { throw new UndeclaredThrowableException(var5); } } public final String load (Long var1) throws { try { return (String)super .h.invoke(this , m3, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final int hashCode () throws { try { return (Integer)super .h.invoke(this , m0, (Object[])null ); } 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" ); m4 = Class.forName("com.wonglay.PersistenceService" ).getMethod("save" , Class.forName("java.lang.Long" ), Class.forName("java.lang.String" )); m3 = Class.forName("com.wonglay.PersistenceService" ).getMethod("load" , Class.forName("java.lang.Long" )); 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.newProxyInstance方法是怎么生成代理类的呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 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<?> cl = getProxyClass0(loader, intfs); 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); } }
继续看这一行代代码 Class<?> cl = getProxyClass0(loader, intfs),点进去会看到如下方法,会先从一个叫WeakCache的缓存类获取代理类,如果获取不到在创建代理类,这个缓存对象是Proxy类的一个成员变量,在JVM加载Proxy类时就会执行赋值操作。
1 2 private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
WeakCache类中获取代理对象的方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public V get (K key, P parameter) { Objects.requireNonNull(parameter); expungeStaleEntries(); Object cacheKey = CacheKey.valueOf(key, refQueue); 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; } } Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null ; while (true ) { if (supplier != null ) { V value = supplier.get(); if (value != null ) { return value; } } if (factory == null ) { factory = new Factory(key, parameter, subKey, valuesMap); } if (supplier == null ) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null ) { supplier = factory; } } else { if (valuesMap.replace(subKey, supplier, factory)) { supplier = factory; } else { supplier = valuesMap.get(subKey); } } } }
接下来再看下代理工厂是怎么生成代理类的,如下是ProxyClassFactory的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 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; 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 ) { proxyPkg = ReflectUtil.PROXY_PACKAGE + "." ; } long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; byte [] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0 , proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); } } }
以上就是整个对JDK动态代理实现原理的分析。
总结 诚然,Proxy 已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持 interface 代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫 Proxy。Java 的继承机制注定了这些动态代理类们无法实现对 class 的动态代理,原因是多继承在 Java 中本质上就行不通。
有很多条理由,人们可以否定对 class 代理的必要性,但是同样有一些理由,相信支持 class 动态代理会更美好。接口和类的划分,本就不是很明显,只是到了 Java 中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。但是如果必须代理类,CGLIB是一个不错的选择。