jdk动态代理: 从源码,到字节码,到自己手写动态代理
注意
本篇文章,讲解非常详细.已经到了字节码层面.内容和篇幅较多.请有耐心,并按照源码依依查看.
反编译查看: 动态代理生成的字节码
分析: 所有的方法处理,都转发给InvocationHandler
源码分析: Proxy.newProxyInstance()
作用: 安全校验,Class反射构造器创建对象
获取所有接口
获取动态对象的Class
反射获取构造器
通过构造器,创建对象
核心: Class cl = getProxyClass0(loader,infs)
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{// lzy分析: null判断Objects.requireNonNull(h);// lzy分析: 获取所有需要动态代理的接口final Class<?>[] intfs = interfaces.clone();// lzy分析: 系统安全校验器final SecurityManager sm = System.getSecurityManager();if (sm != null) {// lzy分析: 安全校验checkProxyAccess(Reflection.getCallerClass(), loader, intfs);}/** Look up or generate the designated proxy class.*/// lzy分析(核心): 生成代理类的Class对象Class<?> cl = getProxyClass0(loader, intfs);/** Invoke its constructor with the designated invocation handler.*/try {if (sm != null) {// lzy分析: 安全校验checkNewProxyPermission(Reflection.getCallerClass(), cl);}// lzy分析: 反射获取构造器final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = h;// lzy分析: 判断构造方法权限修饰符.如果没有权限,强制访问.if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {cons.setAccessible(true);return null;}});}// lzy分析: 通过构造方法创建对象.// h是InvocationHandler,代理对象的处理器.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);}}
源码分析: Proxy.getProxyClass0(loader,infs)
// lzy分析: 接口个数限制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// lzy分析: 通过类加载器loader 和 所有代理接口interfaces,从缓存中获取return proxyClassCache.get(loader, interfaces);
源码分析: WeakCache.get()
作用: 获取工厂,利用工厂创建代理对象
类加载获取,已经加载的接口
所有接口进行Hash唯一标识
准备创建工厂
通过工厂创建代理对象
重试机制: 工厂存在问题,循环中将创建新工厂
核心: V value = suppile.get()
public V get(K key, P parameter) {// lzy分析: null指针判断Objects.requireNonNull(parameter);// lzy分析: 将进入ReferenceQueue队列中数据,删除掉expungeStaleEntries();// lzy分析: 类加载器 和 引用队列,存储到WeakReference引用中Object cacheKey = CacheKey.valueOf(key, refQueue);// lazily install the 2nd level valuesMap for the particular cacheKey// lzy分析: 通过类加载器,获取已加载过的接口和接口工厂// key: 类加载器的WeakReference封装// value:// key: 接口元数据// value: 接口工厂(作用: 创建动态代理对象)ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);// lzy分析: 初始化操作,如果是第一次.那么创建一个空的Mapif (valuesMap == null) {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// lzy分析: 将所有接口进行hash唯一标识. 确保对应着一个工厂.Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));// lzy分析: 通过接口元数据对象,尝试性获取工厂Supplier<V> supplier = valuesMap.get(subKey);Factory factory = null;while (true) {// lzy分析: 第一次是没有工厂的.// 这一步在第一次会跳过 , 下面代码将创建工厂// 通常情况下,执行这一步.是在第二次循环.// 因为第一次循环,是在创建工厂// 只有到了第二次循环,工厂才被创建好.if (supplier != null) {// supplier might be a Factory or a CacheValue<V> instance// 利用工厂进行创建V value = supplier.get();if (value != null) {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) {factory = new Factory(key, parameter, subKey, valuesMap);}if (supplier == null) {// 将工厂放入缓存中supplier = valuesMap.putIfAbsent(subKey, factory);if (supplier == null) {// successfully installed Factory// 已经创建好了,为第二次循环作准备.// 第二次循环,可以利用工厂进行创建supplier = factory;}// else retry with winning supplier// lzy分析: 这是工厂的重试机制// 触发条件: V value = supplier.get();// 通过工厂创建对象,是null值} else {// lzy分析: 由于旧工厂存在问题,无法成功创建对// 那么使用新工厂来代替旧工厂.// 意味着: 将进入下一轮循环.用新工厂,创建对象.if (valuesMap.replace(subKey, supplier, factory)) {// successfully replaced// cleared CacheEntry / unsuccessful Factory// with our Factorysupplier = factory;} else {// retry with current suppliersupplier = valuesMap.get(subKey);}}}}
源码细节分析: CacheKey.valueOf(key,refQueue)
作用:弱引用,GC触发时一定会被回收.但WeakReference对象本身,将进入到ReferenceQueue中
private static final class CacheKey<K> extends WeakReference<K> {static <K> Object valueOf(K key, ReferenceQueue<K> refQueue) {return key == null// null key means we can't weakly reference it,// so we use a NULL_KEY singleton as cache key? NULL_KEY// non-null key requires wrapping with a WeakReference: new CacheKey<>(key, refQueue);}}
源码细节分析: WeakCache.expungeStaleEntries()
作用: 每次创建动态代理时,都会先清理一遍因GC触发而保留下来的Reference中引用.
private void expungeStaleEntries() {CacheKey<K> cacheKey;while ((cacheKey = (CacheKey<K>)refQueue.poll()) != null) {cacheKey.expungeFrom(map, reverseMap);}}
源码细节分析: Proxy.KeyFactory.apply()
作用: 将所有接口进行hash值.确保唯一标识,对应着一个工厂
位置: subkeyFactory.apply(key,parameter)
private static final class KeyFactoryimplements BiFunction<ClassLoader, Class<?>[], Object>{@Overridepublic Object apply(ClassLoader classLoader, Class<?>[] interfaces) {switch (interfaces.length) {case 1: return new Key1(interfaces[0]); // the most frequentcase 2: return new Key2(interfaces[0], interfaces[1]);case 0: return key0;default: return new KeyX(interfaces);}}}
源码分析: WeakCache.get()
作用: 中间层,创建好的对象. 实行WeakReference弱引用
核心: valueFactory.apply(key,paramteter)
public synchronized V get() { // serialize access// re-checkSupplier<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 loopreturn null;}// else still us (supplier == this)// create new valueV value = null;try {value = Objects.requireNonNull(valueFactory.apply(key, parameter));} finally {if (value == null) { // remove us on failurevaluesMap.remove(subKey, this);}}// the only path to reach here is with non-null valueassert value != null;// wrap value with CacheValue (WeakReference)CacheValue<V> cacheValue = new CacheValue<>(value);// put into reverseMapreverseMap.put(cacheValue, Boolean.TRUE);// try replacing us with CacheValue (this should always succeed)if (!valuesMap.replace(subKey, this, cacheValue)) {throw new AssertionError("Should not reach here");}// successfully replaced us with new CacheValue -> return the value// wrapped by itreturn value;}
源码分析:Proxy.ProxyClassFactory.apply()
作用: 创建代理对象准备工作. 检验接口,代理类名称
核心: ProxyGenerator.generateProxyClass()
核心: defineClass0()
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);// lzy分析: 对所有接口进行校验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 + ".";}/** Choose a name for the proxy class to generate.*/// lzy分析:采用并发安全的操作,动态代理的名称自增1long num = nextUniqueNumber.getAndIncrement();String proxyName = proxyPkg + proxyClassNamePrefix + num;/** Generate the specified proxy class.*/// lzy分析: 生成动态代理类的字节码文件.即$Proxy.classbyte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);try {// lzy分析: 字节码文件,加载到JVM虚拟机内存中.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());}}}
源码分析: Proxy.defineClass0()
作用: 将字节码文件,加载到内存中
private static native Class<?> defineClass0(ClassLoader loader, String name,byte[] b, int off, int len);
这里是一个本地方法,不做分析.如果我们想达到相同效果,可以自定义一个类加载器.如下:
public class MyClassLoader extends ClassLoader {private byte[] bytes;public MyClassLoader(byte[] bytes){this.bytes = bytes;}public Class<?> findClass(String name) throws ClassNotFoundException {return defineClass(name,bytes,0,bytes.length);}}
源码分析: ProxyGenerator.generateProxyClass()
核心: var3.generateClassFile()
// lzy分析: 动态代理创建者对象ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);// lzy分析: 利用创建者对象,开始创建final byte[] var4 = var3.generateClassFile();// lzy分析: 将生成的字节码二进制流,保存到本地文件if (saveGeneratedFiles) {AccessController.doPrivileged(new PrivilegedAction<Void>() {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));Files.createDirectories(var3);var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");} else {var2 = Paths.get(var0 + ".class");}Files.write(var2, var4, new OpenOption[0]);return null;} catch (IOException var4x) {throw new InternalError("I/O exception saving generated file: " + var4x);}}});}
理论探讨
接下来工作,我们将生成动态代理的字节码文件.即,$Proxy.class.我们将到操作字节码的层面.问题: 怎么样操作字节码?通常方式有两种.第一种是ASM框架,第二种方式是javassist框架.ASM框架是指令层面的框架,使用技术要求高,必须懂得JVM指令和字节码.运行速度更快.javassist框架是高度封装的框架,使用门槛低,不需懂JVM.运行速度偏慢.jdk中动态代理是如何实现的呢?它既没有采用ASM框架,也没有采用javassist框架.它简单粗暴按照JVM字节码规范,强行用字节流进行写入.当做一个文本文件一样,先写入一个4字节的魔术号,再写入一个2字节的大版本号,2字节的小版本号,依次按照特定规范写入.整个过程,非常原始和底层.没有进行任何过多的二次封装.字节码规范: 强制按照先后顺序,并且指定大小1. 魔术号(4字节)2. 大版本号(2字节)3. 小版本号(2字节)4. 常量池大小(2字节)5. 常量池6. 访问修饰符(2字节)7. 当前类(2字节)8. 父类(2字节)9. 接口个数(2字节)10.接口11. 字段个数(2字节)12. 字段13. 方法个数(2字节)14. 方法15. 属性个数(2字节)16. 属性
源码分析: ProxyGenerator.generateClassFile()
作用: 生成字节码文件.本质是,写入一个字节流
核心流程:// 作用: 生成字节码文件generateClassFile(): 建立IO流,向其中写入字节第一部分: 添加三个固定方法的动态代理hashCode(),equals(),toString()第二部分: 获取所有的接口循环遍历: 将接口所有的方法,建立动态代理核心: this.addProxyMethod(var8, var4);注意: 这里仅仅是解析数据,将数据进行封装.没有开始真正的生成字节码.第三部分: 检查所有代理方法的返回类型checkReturnTypes()第四部分:1. 添加构造方法 this.methods.add(this.generateConstructor());2. 生成代理方法的字节码(核心): 利用第二部分解析的元素// 生成字段的字节码// 作用: 每个动态代理的方法,都需要一个Method的反射类引用进行指向this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));// 生成方法的字节码this.methods.add(var16.generateMethod());第五部分: 写入类的字节码1. 魔术(4个字节)注意: 这里的魔术不是0xCAFEBABY,动态代理生成的有些特殊.var14.writeInt(-889275714);2. 大版本号(2字节)var14.writeShort(0);3. 小版本号(2字节)var14.writeShort(49);4. 常量池: 向常量池中的每一项,写入数据// 作用: 创建常量池// 第一步: 魔术号 + 大版本号 + 小版本号 + 常量池大小// 第二步: 写入每一项的数据. 每个项的组成: 1. 标识 2.数据this.cp.write(var14); //注意: 常量池的解析早就完成,这一步已经到了写入字节码5. 类的权限修饰符var14.writeShort(this.accessFlags);6. 当前类var14.writeShort(this.cp.getClass(dotToSlash(this.className)));7. 父类var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));8. 接口大小var14.writeShort(this.interfaces.length);9. 生成接口相关信息for(int var19 = 0; var19 < var18; ++var19) {Class var22 = var17[var19];var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));}10. 字段大小var14.writeShort(this.fields.size());11. 写入字段相关信息while(var15.hasNext()) {ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();var20.write(var14);}12. 方法大小var14.writeShort(this.methods.size());13. 写入方法相关信息while(var15.hasNext()) {ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();var21.write(var14);}14. 写入空指令var14.writeShort(0)
private byte[] generateClassFile() {// 第一部分: 添加方法的元数据信息. 只是准备阶段.还没有开始生成字节码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);}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();// 第三部分: 生成字段的字节码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() > 65535) {throw new IllegalArgumentException("method limit exceeded");} else if (this.fields.size() > 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);}}}
源码细节分析: ProxyGenerator.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);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 {// lzy分析: 初始化// key: 方法名+方法描述符// value: ArrayListvar8 = new ArrayList(3);this.proxyMethods.put(var7, var8);}// 数据准备: 创建动态代理的核心信息.将依照这些元数据信息,产生代理类的方法信息.((List)var8).add(new ProxyGenerator.ProxyMethod(var3, var4, var5, var6, var2));}
源码细节分析:ProxyGenerator.generateConstructor()
作用: 构造方法的字节码生成
注意: 我们将仔细分析,MethodInfo的构造方法(在下面)
// 创建方法信息类: 指定方法名 和 描述符 和 访问修饰符ProxyGenerator.MethodInfo var1 = new ProxyGenerator.MethodInfo("<init>", "(Ljava/lang/reflect/InvocationHandler;)V", 1);// 准备一个IO流: 此流最终写入到字节码文件中DataOutputStream var2 = new DataOutputStream(var1.code);// 获取局部变量表中下标0位置的数据,即thisthis.code_aload(0, var2);// 获取局部变量表下标1位置的数据,即InvocationHandlerthis.code_aload(1, var2);// 调用超类构造器 0xb7 invokespecialvar2.writeByte(183);// 获取常量池中方法的下标. 作用: 调用父类Proxy中的有参构造方法var2.writeShort(this.cp.getMethodRef("java/lang/reflect/Proxy", "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));// 方法返回值void 0xb1 returnvar2.writeByte(177);// 方法的操作数栈最大深度var1.maxStack = 10;// 局部变量表大小var1.maxLocals = 2;// 异常表var1.declaredExceptions = new short[0];return var1;
源码细节分析: ProxyGenerator.MethodInfo()
作用: 将方法相关信息. 生成字节码写入IO流中. 写入到常量池中
public MethodInfo(String var2, String var3, int var4) {// 方法名称this.name = var2;// 方法描述符this.descriptor = var3;// 方法的权限修饰符this.accessFlags = var4;// 尝试将这些信息放入常量池ProxyGenerator.this.cp.getUtf8(var2);ProxyGenerator.this.cp.getUtf8(var3);ProxyGenerator.this.cp.getUtf8("Code");ProxyGenerator.this.cp.getUtf8("Exceptions");}
源码细节分析:ProxyGenerator.ConstantPool.getUtf8()
原理: 尝试从常量池中获取. 如果没有,就保存到常量池中,并建立缓存.
public short getUtf8(String var1) {if (var1 == null) {throw new NullPointerException();} else {return this.getValue(var1);}}调用关系: getValue()private short getValue(Object var1) {Short var2 = (Short)this.map.get(var1);if (var2 != null) {return var2;} else if (this.readOnly) {throw new InternalError("late constant pool addition: " + var1);} else {short var3 = this.addEntry(new ProxyGenerator.ConstantPool.ValueEntry(var1));this.map.put(var1, new Short(var3));return var3;}}调用关系: addEntry()private short addEntry(ProxyGenerator.ConstantPool.Entry var1) {this.pool.add(var1);if (this.pool.size() >= 65535) {throw new IllegalArgumentException("constant pool size limit exceeded");} else {return (short)this.pool.size();}}
分析: 常量池类
private static class ConstantPool {// 封装的功能类: 常量池中数据最终写入文件中.// Enrty是封装了具有IO流功能的常量池项.// 包含了: 写入的细节private List<ProxyGenerator.ConstantPool.Entry> pool;// key: 字符串标识// value: 在常量池中的下标private Map<Object, Short> map}
继承体系分析: 两个子类class ValueEntry extends ProxyGenerator.ConstantPool.Entryclass IndirectEntry extends ProxyGenerator.ConstantPool.Entry两个类的职责不同:ValueEntry处理基本数据类型IndirectEntry处理其他的特殊类型.方法字段等等.
分析: ValueEntry
第一部分: 标识
第二部分: 真实数据
private static class ValueEntry extends ProxyGenerator.ConstantPool.Entry {private Object value;public void write(DataOutputStream var1) throws IOException {if (this.value instanceof String) {var1.writeByte(1);var1.writeUTF((String)this.value);} else if (this.value instanceof Integer) {var1.writeByte(3);var1.writeInt((Integer)this.value);} else if (this.value instanceof Float) {var1.writeByte(4);var1.writeFloat((Float)this.value);} else if (this.value instanceof Long) {var1.writeByte(5);var1.writeLong((Long)this.value);} else {if (!(this.value instanceof Double)) {throw new InternalError("bogus value entry: " + this.value);}var1.writeDouble(6.0D);var1.writeDouble((Double)this.value);}}}
分析:IndirectEntry
第一部分: 标识符
第二部分: 真实数据
第三部分: 真实数据
private static class IndirectEntry extends ProxyGenerator.ConstantPool.Entry {private int tag;private short index0;private short index1;public void write(DataOutputStream var1) throws IOException {var1.writeByte(this.tag);var1.writeShort(this.index0);if (this.tag == 9 || this.tag == 10 || this.tag == 11 || this.tag == 12) {var1.writeShort(this.index1);}}}
:CONSTANT_Filedref_info 9CONSTANT_Methodref_info 10CONSTANT_InterfaceMethodref_info 11CONSTANT_NameAndType_info 12为什么要这样设计?因为这四类数据,他的值有两部分.一部分,无法表示完整.两部分u2 name_index;u2 descriptor_index;: 方法或字段的名称索引: 描述符的索引
源码分析:ProxyGenerator.ProxyMethod.generateMethod()
动态代理: 生成源码 return (String)super.h.invoke(this, A.m2, null);Java代码: super.h字节码操作:// 180的实际含义: JVM操作指令getField:0xB4 转十进制180var9.writeByte(180);// 获取字段: Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler// 在常量池中的索引,最终返回18var9.writeShort(ProxyGenerator.this.cp.getFieldRef("java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;"));java代码: A.m2// 178的实际含义: JVM操作指令getStatic:0xB2 转十进制178var9.writeByte(178);// 获取字段: A.m2 Ljava/lang/reflect/Method;// 在常量池中的索引var9.writeShort(ProxyGenerator.this.cp.getFieldRef(ProxyGenerator.dotToSlash(ProxyGenerator.this.className), this.methodFieldName, "Ljava/lang/reflect/Method;"));分析源码:if (this.parameterTypes.length > 0) {// 将数据大小,压入到操作数栈中ProxyGenerator.this.code_ipush(this.parameterTypes.length, var9);// 数据创建指令.anewarrayvar9.writeByte(189);// 获取常量池中java/lang/Object的索引,写入到操作数栈中var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/Object"));//for(int var10 = 0; var10 < this.parameterTypes.length; ++var10) {// 复制栈顶数据.即Object数组// 作用: 指令是一次性的.每次复制,都需要从局部变量表中获取Object数组的引用var9.writeByte(89);// 将常量压入到操作数栈中(每次循环增加一个): 0 , 1 ,2 , 3.....// 作用: Object数组初始化,从0开始ProxyGenerator.this.code_ipush(var10, var9);// 类型兼容转换方法// 作用: 因为数组作用是方法的参数列表,但是参数类型肯定不一定是Object// 需要通过类型判断,存储正确的类型到Object数组中// this.parameterTypes[var10] 获取一个Class类型. 判断参数类型的依据// var3[var10]真实的数据. 按情况,对数据类型作出一些调整.// var9字节码输出流.// 例如: Integer,Byte,Short,Char,Boolean 在JVM层面都当做int来处理// 我们需要将引用数据类型的Integer,拆箱成int类型this.codeWrapArgument(this.parameterTypes[var10], var3[var10], var9);// 十进制83 转换 十六进制0x53. JVM指令aastore// 作用: 将引用数据类型存储到局部变量表中var9.writeByte(83);}} else {var9.writeByte(1);}解析:判断方法调用时,需要多少个形式参数.如果大于0,需要参数.//否则.传递null// 十进制1 转成 16进制0x01. JVM指令集中:var9.writeByte(1);Java源码:// 十进制185 转 十六进制0xb9// 作用: invokeInteger指令 调用接口var9.writeByte(185);// 获取接口在常量池中的索引// 为调用指令作准备var9.writeShort(ProxyGenerator.this.cp.getInterfaceMethodRef("java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"));Java源码:// 将1压入操作数栈var9.writeByte(4);// nop无操作指令// 不清楚,为什么这里填写一个这样指令???var9.writeByte(0);// 如果是void,无需返回值,也无需类型转换if (this.returnType == Void.TYPE) {// 87 --> 0x57 --> pop指令: 弹出栈的数据var9.writeByte(87);// 177 --> 0xb1 --> return指令.结束方法var9.writeByte(177);} else {// 检查类型转换this.codeUnwrapReturnValue(this.returnType, var9);}注意:异常部分,不作分析.涉及到方法的异常表.
源码:
private ProxyGenerator.MethodInfo generateMethod() throws IOException {String var1 = ProxyGenerator.getMethodDescriptor(this.parameterTypes, this.returnType);ProxyGenerator.MethodInfo var2 = ProxyGenerator.this.new MethodInfo(this.methodName, var1, 17);int[] var3 = new int[this.parameterTypes.length];int var4 = 1;for(int var5 = 0; var5 < var3.length; ++var5) {var3[var5] = var4;var4 += ProxyGenerator.getWordsPerType(this.parameterTypes[var5]);}byte var7 = 0;DataOutputStream var9 = new DataOutputStream(var2.code);ProxyGenerator.this.code_aload(0, var9);var9.writeByte(180);var9.writeShort(ProxyGenerator.this.cp.getFieldRef("java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;"));ProxyGenerator.this.code_aload(0, var9);var9.writeByte(178);var9.writeShort(ProxyGenerator.this.cp.getFieldRef(ProxyGenerator.dotToSlash(ProxyGenerator.this.className), this.methodFieldName, "Ljava/lang/reflect/Method;"));if (this.parameterTypes.length > 0) {ProxyGenerator.this.code_ipush(this.parameterTypes.length, var9);var9.writeByte(189);var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/Object"));for(int var10 = 0; var10 < this.parameterTypes.length; ++var10) {var9.writeByte(89);ProxyGenerator.this.code_ipush(var10, var9);this.codeWrapArgument(this.parameterTypes[var10], var3[var10], var9);var9.writeByte(83);}} else {var9.writeByte(1);}var9.writeByte(185);var9.writeShort(ProxyGenerator.this.cp.getInterfaceMethodRef("java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"));var9.writeByte(4);var9.writeByte(0);if (this.returnType == Void.TYPE) {var9.writeByte(87);var9.writeByte(177);} else {this.codeUnwrapReturnValue(this.returnType, var9);}short var6;short var8 = var6 = (short)var2.code.size();List var13 = ProxyGenerator.computeUniqueCatchList(this.exceptionTypes);if (var13.size() > 0) {Iterator var11 = var13.iterator();while(var11.hasNext()) {Class var12 = (Class)var11.next();var2.exceptionTable.add(new ProxyGenerator.ExceptionTableEntry(var7, var8, var6, ProxyGenerator.this.cp.getClass(ProxyGenerator.dotToSlash(var12.getName()))));}var9.writeByte(191);var6 = (short)var2.code.size();var2.exceptionTable.add(new ProxyGenerator.ExceptionTableEntry(var7, var8, var6, ProxyGenerator.this.cp.getClass("java/lang/Throwable")));ProxyGenerator.this.code_astore(var4, var9);var9.writeByte(187);var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/reflect/UndeclaredThrowableException"));var9.writeByte(89);ProxyGenerator.this.code_aload(var4, var9);var9.writeByte(183);var9.writeShort(ProxyGenerator.this.cp.getMethodRef("java/lang/reflect/UndeclaredThrowableException", "<init>", "(Ljava/lang/Throwable;)V"));var9.writeByte(191);}if (var2.code.size() > 65535) {throw new IllegalArgumentException("code size limit exceeded");} else {var2.maxStack = 10;var2.maxLocals = (short)(var4 + 1);var2.declaredExceptions = new short[this.exceptionTypes.length];for(int var14 = 0; var14 < this.exceptionTypes.length; ++var14) {var2.declaredExceptions[var14] = ProxyGenerator.this.cp.getClass(ProxyGenerator.dotToSlash(this.exceptionTypes[var14].getName()));}return var2;}}
理论探讨
jdk最开始技术并不成熟,没有出现字节码框架这种东西.导致动态代理源码,在字节码层面显得十分复杂.接下来,我们将使用javassist字节码框架,来实现动态代理.
自定义类加载器
public class MyClassLoader extends ClassLoader {private byte[] bytes;public MyClassLoader(byte[] bytes){this.bytes = bytes;}public Class<?> findClass(String name) throws ClassNotFoundException {return defineClass(name,bytes,0,bytes.length);}}
手写动态代理
依赖:<dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.27.0-GA</version></dependency>
public class MyProxy {private final static String name ="$Proxy";private static int i = 0;protected static InvocationHandler h;public MyProxy(InvocationHandler handler) {h = handler;}public static Object newProxyInstance(Class[] cls, InvocationHandler handler) throws NotFoundException, CannotCompileException, IOException {// 代理类名String proxyName = name+(i++);// 处理器h = handler;// 常量池中添加字节码ClassPool pool = ClassPool.getDefault();// 新建一个字节码CtClass ctClass = pool.makeClass(proxyName);// 设置父类为当前类ctClass.setSuperclass(pool.get("d1.proxy.MyProxy"));// 接口for (Class c : cls) {// 实现接口ctClass.addInterface(pool.get("java.lang.Comparable"));// 添加成员属性: Method,保存方法的反射Method[] declaredMethods = c.getDeclaredMethods();for (int i1 = 0; i1 < declaredMethods.length; i1++) {String code = String.format("private static java.lang.reflect.Method %smethod%d = Class.forName(\"%s\").getDeclaredMethods()[%d];" , c.getSimpleName(), i1, c.getName(), i1);CtField m0 = CtField.make(code, ctClass);ctClass.addField(m0);// 重写方法CtClass[] paramClass = new CtClass[declaredMethods[i1].getParameterTypes().length];for (int i2 = 0; i2 < declaredMethods[i1].getParameterTypes().length; i2++) {String typeName = declaredMethods[i1].getParameterTypes()[i2].getName();paramClass[i2] = pool.get(typeName);}CtMethod method = new CtMethod(pool.get(declaredMethods[i1].getReturnType().getName()), declaredMethods[i1].getName(), paramClass, ctClass);method.setModifiers(Modifier.PUBLIC);// 为什么写的这么麻烦? 因为没有通过java编译器,所以无法自动装箱和拆箱.// 这里留下一个缺陷: 硬编码一下,留下改进的空间method.setBody("{Integer a = (Integer)super.h.invoke(this, null, $args);return a.intValue();}");ctClass.addMethod(method);}}// 构造方法CtConstructor ctConstructor = new CtConstructor(new CtClass[]{pool.get("java.lang.reflect.InvocationHandler")}, ctClass);ctConstructor.setBody("super($1);");ctClass.addConstructor(ctConstructor);// 类加载器MyClassLoader student = new MyClassLoader(ctClass.toBytecode());try {Class<?> c = student.findClass(proxyName);Constructor<?> constructor = c.getConstructor(InvocationHandler.class);return constructor.newInstance(h);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}return null;}}
测试动态代理
public class Demo02 {// file:///home/liziyun/Desktop/动态代理public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Comparable c = (Comparable)MyProxy.newProxyInstance(new Class[]{Comparable.class}, new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("执行");return args[0];}});c.compareTo(11);}}
