以往开发过程中,我们的代码中往往充斥这大量的日志记录、异常处理等与业务不相干的东西,导致代码冗余且不利于后续维护。AOP概念为解决这一问题相应而生,而AOP的基本实现就是这里所要讲述的代理机制。
代理分为静态代理和动态代理,静态代理为每一个要被代理的类新建一个代理类即可,比较简单在此不做解释。
动态代理分为两种:一种是jdk动态代理,一种是cglib动态代理。
JDK动态代理实现分为两个步骤。
注:不要把实现InvocationHandler接口的调度处理器当作代理类,真正生成代理类的其实是Proxy,而生成的代理类的类名是com.sun.proxy.$Proxy*(*是一个number),具体如何生成的下面会详细讲述。
在看调用demo之前,我们先看下使用JDK动态代理需要用到的基本方法。
InvocationHandler接口定义的方法:
/** * @param proxy proxy生成的代理对象 * @param method 真实类的方法(真实类指的是被代理的类,demo中的"GreetingImpl") * @param args 真实类的方法执行参数 */ public abstract Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
Proxy类的newProxyInstance方法:
/** * @param classLoader 真实类的类加载器 * @param interfaces 真实类的实现接口 * @param handler 实现上述接口InvocationHandler的调度处理器对象 */ public static Object newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){ //... }
调用Demo如下:
greeting接口定义:
package test.interfaces; public interface Greeting { void speak(String word); }
greetingImpl实现定义:
package test; import test.interfaces.Greeting; public final class GreetingImpl implements Greeting{ @Override public final void speak(String word) { System.out.println("I want say: " + word); } }
greetingHandler(调度处理器)定义:
package test.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class GreetingJDKProxyHandler implements InvocationHandler { private Object obj; // object为真实对象(被代理对象) public GreetingJDKProxyHandler(Object object) { obj = object; } @Override public Object invoke(Object target, Method method, Object[] params) throws Throwable { // 函数执行前插入的操作 System.out.println("执行前!"); // 真实对象 执行函数 Object rst = method.invoke(obj, params); // 函数执行后插入的操作 System.out.println("执行后!"); return rst; } // 封装方法用来获取jdk Proxy生成的代理对象 public Object getJdkProxy() { // newProxyInstance参数参见上面 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this); } }
调用实例:
package test; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.util.Arrays; import sun.misc.ProxyGenerator; import test.interfaces.Greeting; import test.proxy.GreetingJDKProxyHandler; public class TestJDK { public static void main(String[] args) { jdkProxyDemo(); } public static void jdkProxyDemo() { GreetingImpl impl = new GreetingImpl(); GreetingJDKProxyHandler jdkProxyHandler = new GreetingJDKProxyHandler( impl); Greeting gretting = (Greeting) jdkProxyHandler.getJdkProxy(); System.out.println("父类:" + gretting.getClass().getSuperclass().getName()); System.out.println("接口:" + Arrays.toString(gretting.getClass().getInterfaces())); System.out.println(gretting.getClass().getName()); gretting.speak("Hello World!"); System.out.println(); // 将生成的代理类class文件,输出到本地文件中(用于反编译查看类接口) output(gretting.getClass().getName(), "D://Temp//" + gretting.getClass().getName() + ".class"); } // 把代理类的字节码保存到硬盘上 public static void output(String proxyClassName, String path) { // ProxyGenerator提供了获取代理对象字节流的方法generateProxyClass byte[] file = ProxyGenerator.generateProxyClass(proxyClassName, GreetingImpl.class.getInterfaces()); FileOutputStream out = null; try { out = new FileOutputStream(path); out.write(file); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * @param classLoader * 真实类的类加载器 * @param interfaces * 真实类的实现接口 * @param handler * 实现上述接口InvocationHandler的handler对象 */ public static Object newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler) { // ... return null; }; }执行结果:
从执行的结果中我们可以看出,代理对象的引用(greeting)在执行speak方法时,会调用GreetingHandler类的invoke方法。另外也可以看出代理类是继承自Proxy类,并实现了真实类的Greeting接口(所以才能将代理对象赋给Greeting类型的引用greeting)。
正是因为代理类继承自Proxy类,所以JDK动态代理只能代理实现某一接口的类(假如代理类不实现任何接口,那么生成的代理对象要想赋值给真实类的引用,其类型就必须是真实类的子类才符合多态性。而代理类的父类已经是Proxy,这显然与Java的多继承互相矛盾,这种情况下可以我们可以使用cglib代理)。
Proxy是怎么样生成代理类com.sun.proxy.$Proxy0的呢,代理对象在执行speak方法时,又是怎样去调用GreetingHandler实例的invoke方法呢,我们可以结合源码以及代理类的字节码来分析一下大致流程。
Proxy源码分析:
/* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.lang.reflect; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.security.AccessController; import java.security.Permission; import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import sun.misc.ProxyGenerator; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; /** * {@code Proxy} provides static methods for creating dynamic proxy classes and * instances, and it is also the superclass of all dynamic proxy classes created * by those methods. * * <p> * To create a proxy for some interface {@code Foo}: * * <pre> * InvocationHandler handler = new MyInvocationHandler(...); * Class proxyClass = Proxy.getProxyClass( * Foo.class.getClassLoader(), new Class[] { Foo.class }); * Foo f = (Foo) proxyClass. * getConstructor(new Class[] { InvocationHandler.class }). * newInstance(new Object[] { handler }); * </pre> * * or more simply: * * <pre> * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), * new Class[] { Foo.class }, handler); * </pre> * * <p> * A <i>dynamic proxy class</i> (simply referred to as a <i>proxy class</i> * below) is a class that implements a list of interfaces specified at runtime * when the class is created, with behavior as described below. * * A <i>proxy interface</i> is such an interface that is implemented by a proxy * class. * * A <i>proxy instance</i> is an instance of a proxy class. * * Each proxy instance has an associated <i>invocation handler</i> object, which * implements the interface {@link InvocationHandler}. A method invocation on a * proxy instance through one of its proxy interfaces will be dispatched to the * {@link InvocationHandler#invoke invoke} method of the instance's invocation * handler, passing the proxy instance, a {@code java.lang.reflect.Method} * object identifying the method that was invoked, and an array of type * {@code Object} containing the arguments. The invocation handler processes the * encoded method invocation as appropriate and the result that it returns will * be returned as the result of the method invocation on the proxy instance. * * <p> * A proxy class has the following properties: * * <ul> * <li>Proxy classes are public, final, and not abstract. * * <li>The unqualified name of a proxy class is unspecified. The space of class * names that begin with the string {@code "$Proxy"} should be, however, * reserved for proxy classes. * * <li>A proxy class extends {@code java.lang.reflect.Proxy}. * * <li>A proxy class implements exactly the interfaces specified at its * creation, in the same order. * * <li>If a proxy class implements a non-public interface, then it will be * defined in the same package as that interface. Otherwise, the package of a * proxy class is also unspecified. Note that package sealing will not prevent a * proxy class from being successfully defined in a particular package at * runtime, and neither will classes already defined by the same class loader * and the same package with particular signers. * * <li>Since a proxy class implements all of the interfaces specified at its * creation, invoking {@code getInterfaces} on its {@code Class} object will * return an array containing the same list of interfaces (in the order * specified at its creation), invoking {@code getMethods} on its {@code Class} * object will return an array of {@code Method} objects that include all of the * methods in those interfaces, and invoking {@code getMethod} will find methods * in the proxy interfaces as would be expected. * * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method will return true * if it is passed a proxy class-- a class returned by * {@code Proxy.getProxyClass} or the class of an object returned by * {@code Proxy.newProxyInstance}-- and false otherwise. * * <li>The {@code java.security.ProtectionDomain} of a proxy class is the same * as that of system classes loaded by the bootstrap class loader, such as * {@code java.lang.Object}, because the code for a proxy class is generated by * trusted system code. This protection domain will typically be granted * {@code java.security.AllPermission}. * * <li>Each proxy class has one public constructor that takes one argument, an * implementation of the interface {@link InvocationHandler}, to set the * invocation handler for a proxy instance. Rather than having to use the * reflection API to access the public constructor, a proxy instance can be also * be created by calling the {@link Proxy#newProxyInstance * Proxy.newProxyInstance} method, which combines the actions of calling * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the constructor * with an invocation handler. * </ul> * * <p> * A proxy instance has the following properties: * * <ul> * <li>Given a proxy instance {@code proxy} and one of the interfaces * implemented by its proxy class {@code Foo}, the following expression will * return true: * * <pre> * {@code proxy instanceof Foo} * </pre> * * and the following cast operation will succeed (rather than throwing a * {@code ClassCastException}): * * <pre> * {@code (Foo) proxy} * </pre> * * <li>Each proxy instance has an associated invocation handler, the one that * was passed to its constructor. The static {@link Proxy#getInvocationHandler * Proxy.getInvocationHandler} method will return the invocation handler * associated with the proxy instance passed as its argument. * * <li>An interface method invocation on a proxy instance will be encoded and * dispatched to the invocation handler's {@link InvocationHandler#invoke * invoke} method as described in the documentation for that method. * * <li>An invocation of the {@code hashCode}, {@code equals}, or * {@code toString} methods declared in {@code java.lang.Object} on a proxy * instance will be encoded and dispatched to the invocation handler's * {@code invoke} method in the same manner as interface method invocations are * encoded and dispatched, as described above. The declaring class of the * {@code Method} object passed to {@code invoke} will be * {@code java.lang.Object}. Other public methods of a proxy instance inherited * from {@code java.lang.Object} are not overridden by a proxy class, so * invocations of those methods behave like they do for instances of * {@code java.lang.Object}. * </ul> * * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3> * * <p> * When two or more interfaces of a proxy class contain a method with the same * name and parameter signature, the order of the proxy class's interfaces * becomes significant. When such a <i>duplicate method</i> is invoked on a * proxy instance, the {@code Method} object passed to the invocation handler * will not necessarily be the one whose declaring class is assignable from the * reference type of the interface that the proxy's method was invoked through. * This limitation exists because the corresponding method implementation in the * generated proxy class cannot determine which interface it was invoked * through. Therefore, when a duplicate method is invoked on a proxy instance, * the {@code Method} object for the method in the foremost interface that * contains the method (either directly or inherited through a superinterface) * in the proxy class's list of interfaces is passed to the invocation handler's * {@code invoke} method, regardless of the reference type through which the * method invocation occurred. * * <p> * If a proxy interface contains a method with the same name and parameter * signature as the {@code hashCode}, {@code equals}, or {@code toString} * methods of {@code java.lang.Object}, when such a method is invoked on a proxy * instance, the {@code Method} object passed to the invocation handler will * have {@code java.lang.Object} as its declaring class. In other words, the * public, non-final methods of {@code java.lang.Object} logically precede all * of the proxy interfaces for the determination of which {@code Method} object * to pass to the invocation handler. * * <p> * Note also that when a duplicate method is dispatched to an invocation * handler, the {@code invoke} method may only throw checked exception types * that are assignable to one of the exception types in the {@code throws} * clause of the method in <i>all</i> of the proxy interfaces that it can be * invoked through. If the {@code invoke} method throws a checked exception that * is not assignable to any of the exception types declared by the method in one * of the proxy interfaces that it can be invoked through, then an unchecked * {@code UndeclaredThrowableException} will be thrown by the invocation on the * proxy instance. This restriction means that not all of the exception types * returned by invoking {@code getExceptionTypes} on the {@code Method} object * passed to the {@code invoke} method can necessarily be thrown successfully by * the {@code invoke} method. * * @author Peter Jones * @see InvocationHandler * @since 1.3 */ public class Proxy implements java.io.Serializable { private static final long serialVersionUID = -2222568056686623797L; /** * prefix for all proxy class names * 生成的代理类前缀 */ private final static String proxyClassNamePrefix = "$Proxy"; /** * parameter types of a proxy class constructor * * 代理类的构造方法参数类型(代理类的构造函数里面调用父类Proxy的构造器--Proxy(InvocationHandler * invocationHandler)) */ private final static Class[] constructorParams = { InvocationHandler.class }; /** * maps a class loader to the proxy class cache for that loader * 这个map是用来记录class loader加载代理类的缓存 * weakHashMap是弱引用 会被垃圾回收机制 回收 */ private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache = new WeakHashMap<>(); /** * marks that a particular proxy class is currently being generated * 用来标记一个正在生成的代理类(同一时刻仅能又一个代理类在生成,其他的处于wait()状态) */ private static Object pendingGenerationMarker = new Object(); /** * next number to use for generation of unique proxy class names * 生成代理类的编号 */ private static long nextUniqueNumber = 0; /** * 生成代理类编号的同步锁(防止多个生成的代理类的类名相同) */ private static Object nextUniqueNumberLock = new Object(); /** set of all generated proxy classes, for isProxyClass implementation * 存放已经生成的代理类的class对象, 线程安全的weakHashMap */ private static Map<Class<?>, Void> proxyClasses = Collections .synchronizedMap(new WeakHashMap<Class<?>, Void>()); /** * the invocation handler for this proxy instance. * 这个h是用来存放代理类实例时传入的参数 * @serial */ protected InvocationHandler h; /** * Prohibits instantiation. */ private Proxy() { } /** * Constructs a new {@code Proxy} instance from a subclass (typically, a * dynamic proxy class) with the specified value for its invocation handler. * * 代理类在实例化时,会调用父类的构造器,传入的参数就是调度处理器实例 * * @param h the invocation handler for this proxy instance * */ protected Proxy(InvocationHandler h) { doNewInstanceCheck(); this.h = h; } private static class ProxyAccessHelper { // The permission is implementation specific. static final Permission PROXY_PERMISSION = new ReflectPermission( "proxyConstructorNewInstance"); // These system properties are defined to provide a short-term // workaround if customers need to disable the new security checks. static final boolean allowNewInstance; static final boolean allowNullLoader; static { allowNewInstance = getBooleanProperty("sun.reflect.proxy.allowsNewInstance"); allowNullLoader = getBooleanProperty("sun.reflect.proxy.allowsNullLoader"); } private static boolean getBooleanProperty(final String key) { String s = AccessController .doPrivileged(new PrivilegedAction<String>() { public String run() { return System.getProperty(key); } }); return Boolean.valueOf(s); } static boolean needsNewInstanceCheck(Class<?> proxyClass) { if (!Proxy.isProxyClass(proxyClass) || allowNewInstance) { return false; } if (ReflectUtil.isNonPublicProxyClass(proxyClass)) { for (Class<?> intf : proxyClass.getInterfaces()) { if (!Modifier.isPublic(intf.getModifiers())) { return true; } } } return false; } } /* * Access check on a proxy class that implements any non-public interface. * * @throws SecurityException if a security manager exists, and the caller * does not have the permission. */ private void doNewInstanceCheck() { SecurityManager sm = System.getSecurityManager(); Class<?> proxyClass = this.getClass(); if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(proxyClass)) { try { sm.checkPermission(ProxyAccessHelper.PROXY_PERMISSION); } catch (SecurityException e) { throw new SecurityException("Not allowed to construct a Proxy " + "instance that implements a non-public interface", e); } } } /** * Returns the {@code java.lang.Class} object for a proxy class given a * class loader and an array of interfaces. The proxy class will be defined * by the specified class loader and will implement all of the supplied * interfaces. If a proxy class for the same permutation of interfaces has * already been defined by the class loader, then the existing proxy class * will be returned; otherwise, a proxy class for those interfaces will be * generated dynamically and defined by the class loader. * * <p> * There are several restrictions on the parameters that may be passed to * {@code Proxy.getProxyClass}: * * <ul> * <li>All of the {@code Class} objects in the {@code interfaces} array must * represent interfaces, not classes or primitive types. * * <li>No two elements in the {@code interfaces} array may refer to * identical {@code Class} objects. * * <li>All of the interface types must be visible by name through the * specified class loader. In other words, for class loader {@code cl} and * every interface {@code i}, the following expression must be true: * * <pre> * Class.forName(i.getName(), false, cl) == i * </pre> * * <li>All non-public interfaces must be in the same package; otherwise, it * would not be possible for the proxy class to implement all of the * interfaces, regardless of what package it is defined in. * * <li>For any set of member methods of the specified interfaces that have * the same signature: * <ul> * <li>If the return type of any of the methods is a primitive type or void, * then all of the methods must have that same return type. * <li>Otherwise, one of the methods must have a return type that is * assignable to all of the return types of the rest of the methods. * </ul> * * <li>The resulting proxy class must not exceed any limits imposed on * classes by the virtual machine. For example, the VM may limit the number * of interfaces that a class may implement to 65535; in that case, the size * of the {@code interfaces} array must not exceed 65535. * </ul> * * <p> * If any of these restrictions are violated, {@code Proxy.getProxyClass} * will throw an {@code IllegalArgumentException}. If the {@code interfaces} * array argument or any of its elements are {@code null}, a * {@code NullPointerException} will be thrown. * * <p> * Note that the order of the specified proxy interfaces is significant: two * requests for a proxy class with the same combination of interfaces but in * a different order will result in two distinct proxy classes. * * @param loader * the class loader to define the proxy class * @param interfaces * the list of interfaces for the proxy class to implement * @return a proxy class that is defined in the specified class loader and * that implements the specified interfaces * @throws IllegalArgumentException * if any of the restrictions on the parameters that may be * passed to {@code getProxyClass} are violated * @throws NullPointerException * if the {@code interfaces} array argument or any of its * elements are {@code null} */ @CallerSensitive public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); } return getProxyClass0(loader, interfaces); } /* * Check permissions required to create a Proxy class. * * To define a proxy class, it performs the access checks as in * Class.forName (VM will invoke ClassLoader.checkPackageAccess): * 1."getClassLoader" permission check if loader == null * 2. checkPackageAccess on the interfaces it implements * * To get a constructor and new instance of a proxy class, it performs the * package access check on the interfaces it implements as in * Class.getConstructor. * * If an interface is non-public, the proxy class must be defined by the * defining loader of the interface. If the caller's class loader is not the * same as the defining loader of the interface, the VM will throw * IllegalAccessError when the generated proxy class is being defined via * the defineClass0 method. * * 在生成代理类之前 必须要验证权限 */ private static void checkProxyAccess(Class<?> caller, ClassLoader loader, Class<?>... interfaces) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { ClassLoader ccl = caller.getClassLoader(); if (loader == null && ccl != null) { if (!ProxyAccessHelper.allowNullLoader) { sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); } } ReflectUtil.checkProxyPackageAccess(ccl, interfaces); } } /** * Generate a proxy class. Must call the checkProxyAccess method to perform * permission checks before calling this. * 获取代理类的class对象 */ private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { //接口最大数量 if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } Class<?> proxyClass = null; /* collect interface names to use as key for proxy class cache * 用来生成接口集合 作为cache的Key(cache是loaderToCache的value, loaderToCache的key是loader) */ String[] interfaceNames = new String[interfaces.length]; // for detecting duplicates // 使用set集合 检查重复的接口 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 { //装载接口的class对象 interfaceClass = Class.forName(interfaceName, false, loader); } catch (ClassNotFoundException e) { } //如果传入的接口class对象 和 根据接口名加载器装载生成的class对象 不是同一个 if (interfaceClass != interfaces[i]) { throw new IllegalArgumentException(interfaces[i] + " is not visible from class loader"); } /* * Verify that the Class object actually represents an interface. * 获取的class不是接口类型的class */ 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; } /* * Using string representations of the proxy interfaces as keys in the * proxy class cache (instead of their Class objects) is sufficient * because we require the proxy interfaces to be resolvable by name * through the supplied class loader, and it has the advantage that * using a string representation of a class makes for an implicit weak * reference to the class. * * * 我们有理由用代理接口的字符串形式(集合)代替他们的class对象作为cache的key, * 因为加载器解析代理接口时是根据名字解析的 * (意思就是Class.forName("interface",false,classLoader)) * 而且class使用字符换形式描述,作为class对象的隐式弱引用更好 * (意思是说weakhashMap的key用string形式比class更好)。 * * weakhashMap存放的是 * key:List<String)> intfacesName, * value: new WeakRefrence<Class<?>>(proxycls) * * loaderToCache键对应cache,cache是一个weakhashMap,下面定义的key指的就是weakhashmap的key */ List<String> key = Arrays.asList(interfaceNames); /* * Find or create the proxy class cache for the class loader. * 在loaderToCache中根据classLoader(key)找到或者创建 * 代理类的cache(value,类型是weakhashMap<List<String>,Object>) */ Map<List<String>, Object> cache; //loaderToCache同步锁,保证同一时间 最多只有一个classLoader放进map synchronized (loaderToCache) { cache = loaderToCache.get(loader); if (cache == null) { cache = new HashMap<>(); loaderToCache.put(loader, cache); } /* * This mapping will remain valid for the duration of this method, * without further synchronization, because the mapping will only be * removed if the class loader becomes unreachable. * * 即使没有更深一步的同步,map集合在这个方法中会依然有效,因为这个map只会在 * 类加载器(loader)没有引用的时候,才会被移除。 * * 解释:这个map是weakhashmap,是有可能会被垃圾回收机制处理掉,但是为什么 * 在整个方法中依然有效不被回收呢?那是因为只有map中的key(loader)没有引用的话, * 这个map对应的key-value才会被垃圾回收。(不知道解释对不对) */ } /* * Look up the list of interfaces in the proxy class cache using the * key. This lookup will result in one of three possible kinds of * values: null, if there is currently no proxy class for the list of * interfaces in the class loader, the pendingGenerationMarker object, * if a proxy class for the list of interfaces is currently being * generated, or a weak reference to a Class object, if a proxy class * for the list of interfaces has already been generated. * * 锁定cache防止重复生成代理类 * * 3种可能 * 1.代理类已经生成,代理类的class对象已经存放在cache中,此时直接获取即可。 * 2.要生成的代理类正在生成(请注意描述,不是其他的代理类,就是当前希望生成 * 的代理类正在生成),执行wait()。(等待代理类生成完成后,如果抢到资源执行 * 下层循环时,此时的proxyClass就生成完毕了,此时再执行第1种情况)。 * 3.代理类没生成,作下标记之后,释放cache,继续生成代理类的操作。 */ synchronized (cache) { /* * Note that we need not worry about reaping the cache for entries * with cleared weak references because if a proxy class has been * garbage collected, its class loader will have been garbage * collected as well, so the entire cache will be reaped from the * loaderToCache map. */ do { Object value = cache.get(key); if (value instanceof Reference) { proxyClass = (Class<?>) ((Reference) value).get(); } if (proxyClass != null) { // proxy class already generated: return it return proxyClass; } else if (value == pendingGenerationMarker) { // proxy class being generated: wait for it try { cache.wait(); } catch (InterruptedException e) { /* * The class generation that we are waiting for should * take a small, bounded time, so we can safely ignore * thread interrupts here. */ } continue; } else { /* * No proxy class for this list of interfaces has been * generated or is being generated, so we will go and * generate it now. Mark it as pending generation. * * 标记下key的代理类正在生成 */ cache.put(key, pendingGenerationMarker); break; } } while (true); } try { 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 (int i = 0; i < interfaces.length; i++) { int flags = interfaces[i].getModifiers(); if (!Modifier.isPublic(flags)) { String name = interfaces[i].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 // 设置代理类名 com.sun.proxy. proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } { /* * Choose a name for the proxy class to generate. * 防止生成的代理类名重复 */ long num; synchronized (nextUniqueNumberLock) { num = nextUniqueNumber++; } // 生成的代理类 类名为com.sun.proxy.$Proxy(Number) String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Verify that the class loader hasn't already defined a class * with the chosen name. */ /* * Generate the specified proxy class. * 生成代理类文件的字节流 */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces); try { //调用本地方法(native),获取代理类的class文件 proxyClass = 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()); } } // add to set of all generated proxy classes, for isProxyClass // 将生成的代理类的class对象 放入proxyClasses map中, // 这个是用来判断代理类是否已经生成用的 proxyClasses.put(proxyClass, null); } finally { /* * We must clean up the "pending generation" state of the proxy * class cache entry somehow. If a proxy class was successfully * generated, store it in the cache (with a weak reference); * otherwise, remove the reserved entry. In all cases, notify all * waiters on reserved entries in this cache. */ synchronized (cache) { if (proxyClass != null) { /** * 如果class还存在,接口类放入key中。这个key之前存放的是 * pending generation对象,现在用来存放生成的代理类的class对象 * 的weakReference */ cache.put(key, new WeakReference<Class<?>>(proxyClass)); } else { //如果代理类生成异常,则将key从cache中去掉 cache.remove(key); } //释放cache,让wait()继续执行 cache.notifyAll(); } } return proxyClass; } /** * Returns an instance of a proxy class for the specified interfaces that * dispatches method invocations to the specified invocation handler. This * method is equivalent to: * * <pre> * Proxy.getProxyClass(loader, interfaces) * .getConstructor(new Class[] { InvocationHandler.class }) * .newInstance(new Object[] { handler }); * </pre> * * <p> * {@code Proxy.newProxyInstance} throws {@code IllegalArgumentException} * for the same reasons that {@code Proxy.getProxyClass} does. * * @param loader * the class loader to define the proxy class * 代理类的类加载器 * @param interfaces * the list of interfaces for the proxy class to implement * 代理实现的接口数组 * @param h * the invocation handler to dispatch method invocations to * 调度处理器实例(代理类在执行相关方法时,会调用调度处理器的Invoke方法,传入相应的proxy,method,params参数) * @return a proxy instance with the specified invocation handler of a proxy * class that is defined by the specified class loader and that * implements the specified interfaces * @throws IllegalArgumentException * if any of the restrictions on the parameters that may be * passed to {@code getProxyClass} are violated * @throws NullPointerException * if the {@code interfaces} array argument or any of its * elements are {@code null}, or if the invocation handler, * {@code h}, is {@code null} */ @CallerSensitive /* * Proxy动态生成代理类的入口 */ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); } /* * Look up or generate the designated proxy class. * 动态生成代理类的核心方法,获取代理类的class对象 */ Class<?> cl = getProxyClass0(loader, interfaces); /* * 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, 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()); } } } /** * Returns true if and only if the specified class was dynamically generated * to be a proxy class using the {@code getProxyClass} method or the * {@code newProxyInstance} method. * * <p> * The reliability of this method is important for the ability to use it to * make security decisions, so its implementation should not just test if * the class in question extends {@code Proxy}. * * @param cl * the class to test * @return {@code true} if the class is a proxy class and {@code false} * otherwise * @throws NullPointerException * if {@code cl} is {@code null} */ public static boolean isProxyClass(Class<?> cl) { if (cl == null) { throw new NullPointerException(); } return proxyClasses.containsKey(cl); } /** * Returns the invocation handler for the specified proxy instance. * * 这个方法很有用,根据代理类的实例,我们可以获取到该代理类的调度处理器的实例化对象 * * @param proxy * the proxy instance to return the invocation handler for * @return the invocation handler for the proxy instance * @throws IllegalArgumentException * if the argument is not a proxy instance */ public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException { /* * Verify that the object is actually a proxy instance. */ if (!isProxyClass(proxy.getClass())) { throw new IllegalArgumentException("not a proxy instance"); } Proxy p = (Proxy) proxy; return p.h; } /** * 这个方法是调用本地方法来生成class对象 * @param loader * @param name * @param b * @param off * @param len * @return */ private static native Class defineClass0(ClassLoader loader, String name, byte[] b, int off, int len); }
从源代码中我们可以看到代理类的class对象是调用本地代码(可能是C/C++)执行返回的。不过尽管如此,我们还是能通过一些办法来获取到代理类的class文件。具体方法已经在上面demo的调用实例中说明。
看完源码之后,其实有一个有趣的问题,假如ClassA和ClassB同时实现了相同的多个接口(接口A,接口B...),那我们在对ClassA和ClassB代理的时候会生成几个代理类?又会生成几个代理对象?答案是只生成一个代理类,而这个代理类会生成两个代理对象。原因我就不分析了,源码中讲的算是比较清晰了,有兴趣的请自行查看。
生成的代理类classes文件反编译出来的Java类:
package com.sun.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import test.interfaces.Greeting; /** * 生成的代理类实现Greeting接口并继承自Proxy * 方法中this.h, h是Proxy的非静态成员变量 */ public final class $Proxy0 extends Proxy implements Greeting { private static Method m1; private static Method m3; private static Method m0; private static Method m2; /** * 构造方法中调用父类的构造,而父类的构造器,将paramInvocationHandler * 赋值给变量h,这个h也是继承自Proxy,以便在方法中调用 * @param paramInvocationHandler 用户定义的调度处理器对象 */ public $Proxy0(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler); } public final boolean equals(Object paramObject) { try { return ((Boolean) this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } /** * 调用代理对象的speak方法,并传入参数paramString时, * 会在函数内部调用调度处理器h的invoke方法 */ public final void speak(String paramString) { try { //3个参数 分别是$Proxy0(代理类实例),真实对象的method对象,代理对象的方法参数 this.h.invoke(this, m3, new Object[] { paramString }); return; } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() { try { return ((Integer) this.h.invoke(this, m0, null)).intValue(); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() { try { return (String) this.h.invoke(this, m2, null); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } /** * 这里会将真实对象的interface定义的接口方法以及 * 父类Object的equals、hascode,toString方法 定义成静态变量 * 用于来在代理类中调用对应的烦烦噶 */ static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName("test.interfaces.Greeting").getMethod("speak", new Class[] { Class.forName("java.lang.String") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError( localClassNotFoundException.getMessage()); } } }
从上面我们可以看出,代理类的方法、返回值、参数和被代理的类是一模一样的,而且方法里面的this.h.invoke中的参数method就是被代理的类的method,那么代理对象方法执行的时候又是如何实现被代理对象原有的功能呢,我们接着往下看。
private Object obj; // object为真实对象(被代理对象) public GreetingJDKProxyHandler(Object object) { obj = object; } @Override public Object invoke(Object target, Method method, Object[] params) throws Throwable { // 函数执行前插入的操作 System.out.println("执行前!"); // 真实对象 执行函数 Object rst = method.invoke(obj, params); // 函数执行后插入的操作 System.out.println("执行后!"); return rst; }
<pre name="code" class="java">Object rst = method.invoke(obj, params);//obj是真实对象的实例
cglib代理的实现同样也是两个步骤:
下面是调用demo
GreetingEntity实例:
package test; public class GreetingEntity { public void speak(String word) { System.out.println("I want say: " + word); } }
GreetingCglibProxyHandler实例:
package test.proxy; import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; public class GreetingCglibProxyHandler implements MethodInterceptor{ private Object obj; public GreetingCglibProxyHandler(Object object){ obj = object; } public Object getProxy(){ return Enhancer.create(obj.getClass(),obj.getClass().getInterfaces(),this); } @Override public Object intercept(Object arg0, Method method, Object[] params, MethodProxy methodProxy) throws Throwable { System.out.println("执行前!"); Object rst = methodProxy.invoke(obj, params); System.out.println("执行后!"); return rst; } }
package test; import java.util.Arrays; import test.proxy.GreetingCglibProxyHandler; public class TestCglib{ public static void main(String[] args){ cglibProxyDemo(); } public static void cglibProxyDemo(){ GreetingCglibProxyHandler proxyFactory = new GreetingCglibProxyHandler(new GreetingEntity()); Object object = proxyFactory.getProxy(); GreetingEntity cglibCreate = (GreetingEntity) object; System.out.println("父类:" + cglibCreate.getClass().getSuperclass().getName()); System.out.println("接口:" + Arrays.toString(cglibCreate.getClass().getInterfaces())); System.out.println(cglibCreate.getClass().getName()); cglibCreate.speak("Hello World!"); } }
从调用方式上面,我们可以看出与JDK动态代理的使用方式几乎一样,我就不做解释了,但是他们实现的本质是天差地别的,细心的读者可能已经发现被代理的实例没有实现任何接口。
运行结果:
从运行的结果来看,我们看到CGLIB动态代理生成的代理类是继承自他的父类GreetingEntity的,假如被代理的类实现了Greeting接口,那么生成的代理类也会实现该接口。正是因为CGLIB的这种机制,所以CGLIB代理能够代理普通类(不实现任何接口的类),那么CGLIB代理是否万能呢?当然不是,因为CGLIB生成的代理类继承自被代理的类,所以如果是final类则会抛出异常是无法实现代理的,如果被代理类中有final方法,final方法也是不能被代理的(但是非final方法可以被成功代理,而且final方法虽然无法被代理实现边缘功能,但是其业务层代码是可以被正常执行的,非常人性化的设计)。
Java中实现动态代理的方式有两种,JDK动态代理和CGLIB动态代理。
JDK代理:
特性:实现被代理类的接口并继承自Proxy。
缺点:JDK代理是基于接口的代理,不实现任何接口的类是无法被代理的。
CGLIB代理:
特性:继承自被代理的类,并实现被代理类所实现的接口(如果有的话)。
缺点:CGLIB代理无法代理final类和代理final方法。
无论是哪种代理都有自己的特点,没有绝对的好坏只分,在项目中结合使用的场合用什么代理要根据情况而定才最为稳妥。新版的Spring已经将CGLIB集成进去了,Spring默认用的是JDK动态代理,当然你也可以通过配置去选择。