一、使用示例:
1、定义DTO:
public class User { private String userName; private String passWord; private String email; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassWord() { return passWord; } public void setPassWord(String passWord) { this.passWord = passWord; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } } |
2、定义接口:
public interface UserDao { void addUser(User user); } |
3、实现接口:
public class UserDaoImpl implements UserDao { @Override public void addUser(User user) { System.out.println("connect to mySQL dataBase......."); System.out.println("添加用户信息成功..."); } } |
4、实现被代理对象的增强类:
public class LogHandler implements InvocationHandler { private Object target; public LogHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始记录日志"); method.invoke(target, args); System.out.println("日志记录完成"); return null; } } |
5、调用测试:
public static void main(String[] args) { UserDao dao = new UserDaoImpl(); LogHandler handler = new LogHandler(dao); UserDao proxy = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), handler); proxy.addUser(user); } |
二、动态生成的代理文件查看:
1、在调用动态代理的main方法中加上:
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); |
2、利用ProxyGenerator生成:
public static void main(String[] args) { byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", UserDaoImpl.class.getInterfaces()); String path = "E:\\$Proxy0.class"; try(FileOutputStream fos = new FileOutputStream(path)) { fos.write(classFile); fos.flush(); System.out.println("代理类class文件写入成功"); } catch (Exception e) { System.out.println("写文件错误"); } } |
这样在运行代码的时候就会在项目的根目录(或者指定目录)下生成 com.sun.proxy.$ProxyX.class 了,反编译查看:
public final class $Proxy0 extends Proxy implements UserDao { 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 void addUser(User var1) throws { try { super.h.invoke(this, m3, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } }
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.ucar.test.service.UserDao").getMethod("addUser", Class.forName("com.ucar.test.dto.User")); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } } |
可以看到:
1) 代理类$Proxy0从Proxy派生而来,并且实现了UserDao接口;
2) static块中生成了Object类的三个方法:toString、equals、hashCode,并且也生成了UserDao接口的addUser方法;
3) 调用端通过Proxy.newProxyInstance获取的对象实例也就是这个$Proxy0类型的对象,默认情况下这个类是不保存到磁盘上的,直接在内存中通过ClassLoader加载,因此在断点调试时是无法定位到这个类里面的;
4) 当调用UserDao接口的addUser方法时,其实是调用InvocationHandler.invoke方法,InvocationHandler的实现也就是我们前面实现的LogHandler类,这样就将调用转到LogHandler.invoke方法;
三、源码分析:
1、首先从Proxy.newProxyInstance开始分析:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException{ // null检查,h为null就抛出NullPointerException Objects.requireNonNull(h); // 将接口类对象数组clone一份。 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); } // 是static final 修饰的,源码: private static final Class<?>[] constructorParams ={ InvocationHandler.class }; // 从代理类对象中查找参数为InvocationHandler的构造器 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; // 检测构造器是否是Public修饰,如果不是则强行转换为可以访问的。 if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } // 通过反射,将h作为参数,实例化代理类,返回代理类实例。 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); } } |
这个方法主要工作:
1) getProxyClass0(loader, intfs)方法生成了上面的代理类$Proxy0,生成时主要根据intfs接口获取接口并生成,因此这就是JDK动态代理的类必须要定义接口的愿意;
2) cons.newInstance(new Object[]{h}):利用反射技术实例化代理类,并返回实例化对象;
2、getProxyClass0方法:
/** * 生成一个代理类对象, * Generate a proxy class. Must call the checkProxyAccess method * to perform permission checks before calling this. */ private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { // 接口类对象数组不能大于65535个,否则抛出异常 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); } |
在这个方法中,是直接从一个叫proxyClassCache缓存中读取的,来看一下这个缓存的声明:
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); |
看一下WeakCache类的大概结构:
final class WeakCache<K, P, V> { private final ReferenceQueue<K> refQueue= new ReferenceQueue<>(); // the key type is Object for supporting null key // key的类型为Object,支持null key,这里的null key并不是真的可以使用null最为key,而是一个new Objdec()对象实例。ConcurrentHashMap,不允许键或值null,而HashMap可以。ConcurrentHashMap是线程安全的,HashMap不是。 private final ConcurrentMap<Supplier<V>, Boolean> reverseMap= new ConcurrentHashMap<>();
private final BiFunction<K, P, ?> subKeyFactory; private final BiFunction<K, P, V> valueFactory; //构造方法 public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) { this.subKeyFactory = Objects.requireNonNull(subKeyFactory); this.valueFactory = Objects.requireNonNull(valueFactory); }
public V get(K key, P parameter) { //下面会详细介绍这个方法 } ...... } |
3、WeakCache.get方法:
// key是类加载器,parameter为接口类对象数组 public V get(K key, P parameter) { // 接口类对象数组null检查。 Objects.requireNonNull(parameter);
// 删除过时的条目 expungeStaleEntries(); // 生成缓存key对象实例,如果key = null,cacheKey = new Object(); Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey // 从缓存map中读取指定cacheKey的缓存数据valuesMap ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) { //如果valuesMap为null,则新增 //putIfAbsent方法解释:如果值存在则返回值,并且不对原来的值做任何更改,如果不存在则新增,并返回null //Absent的意思是缺席,不在 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 // 获取subKey,这里用到了上面提到的Proxy的静态内部类KeyFactory:subKeyFactory.apply(ket,parameter) Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); // 从valuesMap中获取supplier Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; while (true) { if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance // 4,从工厂中获取代理类对象 V value = supplier.get(); if (value != null) { // 5,返回 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) { //1,实例化工厂 factory = new Factory(key, parameter, subKey, valuesMap); } if (supplier == null) { //2,保存到valuesMap中 supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { // successfully installed Factory // 3,赋值 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就是factory;
4、Factory.get方法:
private final class Factory implements Supplier<V> { private final K key; private final P parameter; private final Object subKey; private final ConcurrentMap<Object, Supplier<V>> valuesMap; Factory(K key, P parameter, Object subKey, ConcurrentMap<Object, Supplier<V>> valuesMap) { this.key = key; this.parameter = parameter; this.subKey = subKey; this.valuesMap = valuesMap; } @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 { // valueFactory就是WeakCache的valueFactory属性,因为Factory是WeakCache的内部类,所以可以直接访问WeakCache的valueFactory属性 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; } } |
这里最关键的代码:valueFactory.apply(key, parameter);valueFactory就是Proxy的静态内部类ProxyClassFactory;
5、ProxyClassFactory.apply方法:
/** * 一个利用给定的类加载器和接口类数组生成,定义并返回代理类对象的工厂方法 * A factory function that generates, defines and returns the proxy class given * the ClassLoader and array of interfaces. */ private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // prefix for all proxy class names // 所有代理类对象的前缀 private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names // 用于生成唯一代理类名称的下一个数字 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) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class<?> interfaceClass = null; try { // 加载接口类,获得接口类的类对象,第二个参数为false表示不进行实例化 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()); } } // package to define proxy class in // 代理类的包名 String proxyPkg = null; int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * 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)) { 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) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = 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. */ //生成代理类class文件 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags); 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()); } } } } |
这里的ProxyGenerator.generateProxyClass生成了代理类的字节码文件;
6、ProxyGenerator.generateProxyClass方法:
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) { ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2); // 真正用来生成代理类字节码文件的方法在这里 final byte[] var4 = var3.generateClassFile(); // 保存代理类的字节码文件 if(saveGeneratedFiles) { AccessController.doPrivileged(new PrivilegedAction() { public Void run() { try { int var1 = var0.lastIndexOf(46); Path var2; if(var1 > 0) { Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar), new String[0]); Files.createDirectories(var3, new FileAttribute[0]); var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class"); } else { var2 = Paths.get(var0 + ".class", new String[0]); } Files.write(var2, var4, new OpenOption[0]); return null; } catch (IOException var4x) { throw new InternalError("I/O exception saving generated file: " + var4x); } } }); } return var4; } |
其中generateClassFile是真正用于生成代理类字节码文件的方法;saveGeneratedFiles判断是否要将代理类字节码文件保存到本地磁盘文件,其定义为:
private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles")); |
可以看到saveGeneratedFiles是从系统环境变量中读取的”sun.misc.ProxyGenerator.saveGeneratedFiles”变量并转换成布尔类型;
7、generateClassFile方法:
private byte[] generateClassFile() { //下面一系列的addProxyMethod方法是将接口中的方法和Object中的方法添加到代理方法中(proxyMethod) this.addProxyMethod(hashCodeMethod, Object.class); this.addProxyMethod(equalsMethod, Object.class); this.addProxyMethod(toStringMethod, Object.class); Class[] var1 = this.interfaces; int var2 = var1.length; int var3; Class var4; //获得接口中所有方法并添加到代理方法中 for(var3 = 0; var3 < var2; ++var3) { var4 = var1[var3]; Method[] var5 = var4.getMethods(); int var6 = var5.length; for(int var7 = 0; var7 < var6; ++var7) { Method var8 = var5[var7]; this.addProxyMethod(var8, var4); } } Iterator var11 = this.proxyMethods.values().iterator(); //验证具有相同方法签名的方法的返回类型是否一致 List var12; while(var11.hasNext()) { var12 = (List)var11.next(); checkReturnTypes(var12); } //后面一系列的步骤用于写代理类Class文件 Iterator var15; try { //生成代理类的构造函数 this.methods.add(this.generateConstructor()); var11 = this.proxyMethods.values().iterator(); while(var11.hasNext()) { var12 = (List)var11.next(); var15 = var12.iterator(); while(var15.hasNext()) { ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next(); //将代理类字段声明为Method,并且字段修饰符为 private static. //因为 10 是 ACC_PRIVATE和ACC_STATIC的与运算 故代理类的字段都是 private static Method *** this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10)); //生成代理类的方法 this.methods.add(var16.generateMethod()); } } //为代理类生成静态代码块对某些字段进行初始化 this.methods.add(this.generateStaticInitializer()); } catch (IOException var10) { throw new InternalError("unexpected I/O Exception", var10); } if(this.methods.size() > '\uffff') { //代理类中的方法数量超过65535就抛异常 throw new IllegalArgumentException("method limit exceeded"); } else if(this.fields.size() > '\uffff') {// 代理类中字段数量超过65535也抛异常 throw new IllegalArgumentException("field limit exceeded"); } else { // 后面是对文件进行处理的过程 this.cp.getClass(dotToSlash(this.className)); this.cp.getClass("java/lang/reflect/Proxy"); var1 = this.interfaces; var2 = var1.length; for(var3 = 0; var3 < var2; ++var3) { var4 = var1[var3]; this.cp.getClass(dotToSlash(var4.getName())); } this.cp.setReadOnly(); ByteArrayOutputStream var13 = new ByteArrayOutputStream(); DataOutputStream var14 = new DataOutputStream(var13); try { var14.writeInt(-889275714); var14.writeShort(0); var14.writeShort(49); this.cp.write(var14); var14.writeShort(this.accessFlags); var14.writeShort(this.cp.getClass(dotToSlash(this.className))); var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy")); var14.writeShort(this.interfaces.length); Class[] var17 = this.interfaces; int var18 = var17.length; for(int var19 = 0; var19 < var18; ++var19) { Class var22 = var17[var19]; var14.writeShort(this.cp.getClass(dotToSlash(var22.getName()))); } var14.writeShort(this.fields.size()); var15 = this.fields.iterator(); while(var15.hasNext()) { ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next(); var20.write(var14); } var14.writeShort(this.methods.size()); var15 = this.methods.iterator(); while(var15.hasNext()) { ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next(); var21.write(var14); } var14.writeShort(0); return var13.toByteArray(); } catch (IOException var9) { throw new InternalError("unexpected I/O Exception", var9); } } } |
其中addProxyMethod实现将接口与Object中一些方法添加到代理类中;
8、addProxyMethod:
private void addProxyMethod(Method var1, Class<?> var2) { String var3 = var1.getName();//获得方法名称 Class[] var4 = var1.getParameterTypes();//获得方法参数类型 Class var5 = var1.getReturnType();//获得方法返回类型 Class[] var6 = var1.getExceptionTypes();//异常类型 String var7 = var3 + getParameterDescriptors(var4);//获得方法签名 Object var8 = (List)this.proxyMethods.get(var7);//根据方法前面获得proxyMethod的value if(var8 != null) {//处理多个代理接口中方法重复的情况 Iterator var9 = ((List)var8).iterator(); while(var9.hasNext()) { ProxyGenerator.ProxyMethod var10 = (ProxyGenerator.ProxyMethod)var9.next(); if(var5 == var10.returnType) { ArrayList var11 = new ArrayList(); collectCompatibleTypes(var6, var10.exceptionTypes, var11); collectCompatibleTypes(var10.exceptionTypes, var6, var11); var10.exceptionTypes = new Class[var11.size()]; var10.exceptionTypes = (Class[])var11.toArray(var10.exceptionTypes); return; } } } else { var8 = new ArrayList(3); this.proxyMethods.put(var7, var8); } ((List)var8).add(new ProxyGenerator.ProxyMethod(var3, var4, var5, var6, var2, null)); } |
JDK动态代理的原理是根据定义好的规则,用传入的接口创建一个新类,JDK的动态代理只能代理接口中的方法,是针对接口生成代理类。这就是为什么采用动态代理时为什么只能用接口引用指向代理,而不能用传入的类引用执行动态类。
四、参考资料:
https://www.jianshu.com/p/471c80a7e831