获取Proxy生成的字节码
通过ProxyGenerator来查看Proxy生成出的class流。
import sun.misc.ProxyGenerator;import java.io.FileOutputStream;import java.io.IOException;public class ProxyClassGenerator {public static void main(String[] args) throws IOException {generateFile(Cloneable.class);}static void generateFile(Class c) throws IOException {byte[] proxy0s = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{c});FileOutputStream fileOutputStream = new FileOutputStream("./"+c.getName()+".class");fileOutputStream.write(proxy0s);fileOutputStream.close();}}
反编译Proxy生成的类
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 Cloneable {//通过反射来获取具体的实现方法private static Method m1;private static Method m2;private static Method m0;static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m2 = Class.forName("java.lang.Object").getMethod("toString");m0 = Class.forName("java.lang.Object").getMethod("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}/*** 构造器需要*/public $Proxy0(InvocationHandler var1) throws {//调用Proxy(InvocationHandler h),将设置InvocationHandler成员变量h。super(var1);}public final boolean equals(Object var1) throws {try {//通过调用InvocationHandler.invoke方法来触发用户自定义行为。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 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);}}}
重新看Proxy#newProxyInstance
我把SecurityManager相关代码删除了,不影响代码实现的学习。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{//校验h不能为空。Objects.requireNonNull(h);final Class<?>[] intfs = interfaces.clone();/** 查找或生成指定的代理类。*/Class<?> cl = getProxyClass0(loader, intfs);/** 使用指定的调用处理程序调用其构造函数。*/try {final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = 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);}}
接下来就是研究getProxyClass0里面是个啥了,基于上面的试验,可以推断出这是一个生产代理类二进制流,并通过类加载器加载进JVM的方法。
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());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 ProxyClassFactoryreturn proxyClassCache.get(loader, interfaces);}
getProxyClass0方法只做了一次参数校验,看来具体实现在WeakCache里面。然后WeakCache里面七绕八绕之后,最终加载的实现是ProxyClassFactory的apply方法。
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {//一长串对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 inint 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 packageproxyPkg = ReflectUtil.PROXY_PACKAGE + ".";}//生成代理类名long num = nextUniqueNumber.getAndIncrement();String proxyName = proxyPkg + proxyClassNamePrefix + num;/** ProxyGenerator出现了非常好* 生成指定的代理类。*/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());}}/*** 动态加载类* @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);
关于native方法defineClass0
我翻了下OpenJDK8的源码,里面有调用(*env)->DefineClass(env, utfName, loader, body, length)方法来加载类,更底层的就不挖了。
JNIEXPORT jclass JNICALLJava_java_lang_reflect_Proxy_defineClass0(JNIEnv *env,jclass ignore,jobject loader,jstring name,jbyteArray data,jint offset,jint length){jbyte *body;char *utfName;jclass result = 0;char buf[128];if (data == NULL) {JNU_ThrowNullPointerException(env, 0);return 0;}/* Work around 4153825. malloc crashes on Solaris when passed a* negative size.*/if (length < 0) {JNU_ThrowArrayIndexOutOfBoundsException(env, 0);return 0;}body = (jbyte *)malloc(length);if (body == 0) {JNU_ThrowOutOfMemoryError(env, 0);return 0;}(*env)->GetByteArrayRegion(env, data, offset, length, body);if ((*env)->ExceptionOccurred(env))goto free_body;if (name != NULL) {jsize len = (*env)->GetStringUTFLength(env, name);jsize unicode_len = (*env)->GetStringLength(env, name);if (len >= (jsize)sizeof(buf)) {utfName = malloc(len + 1);if (utfName == NULL) {JNU_ThrowOutOfMemoryError(env, NULL);goto free_body;}} else {utfName = buf;}(*env)->GetStringUTFRegion(env, name, 0, unicode_len, utfName);VerifyFixClassname(utfName);} else {utfName = NULL;}result = (*env)->DefineClass(env, utfName, loader, body, length);if (utfName && utfName != buf)free(utfName);free_body:free(body);return result;}
