设计模式(1-2)-动态代理(newProxyInstance)

上节设计模式(1-1)-代理模式,讲了代理模式的静态代理与动态代理的写法。本节,会从Proxy.newProxyInstance() 这个方法开始讲,上一节文末的那个class文件怎么一步步的来的。

UpanSell proxy = (UpanSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), handler );

上面的方法会返回一个指定接口的代理类实例
newProxyInstance
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); ... // 验证权限 .../* * 这里是重中之重, 这里会生成或去缓存中拿指定的代理类 */ Class cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try {...// 下面的逻辑就是拿到代理类的构造器 -> 检测代理类的类修饰符是否是public, 不是就设置为可访问 -> 返回代理类的实例 final Constructor cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch... .... }

【设计模式(1-2)-动态代理(newProxyInstance)】我们debug到getProxyClass0
private static Class getProxyClass0(ClassLoader loader, Class... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); }// 根据loader、interfaces有对应缓存,就直接返回缓存的复制 // 否则,就通过ProxyClassFactory生成代理类 return proxyClassCache.get(loader, interfaces); }

可能你会问为什么有个65535的限制,类中的注释就解释了为什么
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 interfaces array must not exceed 65535.

大致意思就是JVM限制了一个类实现的方法最多是65535(JVM这块确实头疼,还没开始去学习...)
继续debug到ProxyFactory,现在不用关心怎么从get方法到的ProxyFactory,把下一篇文章看完就明白了
ProxyClassFactory,根据指定的classLoader和interfaces生成和返回代理类的一个工厂方法
private static final class ProxyClassFactory implements BiFunction[], Class> { // 所有代理的前缀名, 看到这个玩意儿就证明该类是代理类 private static final String proxyClassNamePrefix = "$Proxy"; // 生成唯一的代理类数字,每个代理类有一个 eg, $Proxy0 private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class apply(ClassLoader loader, Class[] interfaces) {Map, 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; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * 记录且验证非public的代理接口是在同一个包下的 */ 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 = ReflectUtil.PROXY_PACKAGE + "."; }/* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); // 最后的全限定名, eg: com.sun.proxy.$Proxy0 String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * 生成指定的代理类.重点 */ 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()); } } }

下一篇文章会讲为什么proxyClassCache.get(loader, interfaces); 不存在对应loader与interfaces的缓存时,会调用到ProxyFactory的apply()方法。
再下一篇揭露JDK动态代理是如何生成代理类的 -> ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);

    推荐阅读