在设计模式中,代理模式是经常会用到的一种模式。但是光说设计模式,没有实际意义。在Mybatis源码系列中,用到了该设计模式,因此,我们结合Mybatis使用的代理模式过程,来分析下如何使用代理模式,代理模式的核心是什么。
一、基于接口的代理模式
在讲代理模式的时候,我想起在大话模式中讲的一个故事。A暗恋B,想给B送个礼物,但是又不能直接给B送去。因此,它去礼物店,买了一件礼物,告诉店员心仪的B的信息,让店员送过去,这里,店员就帮忙完成了A想送礼物给B的事情。这里的店员,就是代理者的角色。
那我们用代码如何去实现以上过程呢?我们首先讲第一种方式---静态代理模式。
1、静态代理
为什么叫静态代理模式?当然是相对于动态来说,在我们不知道静态代理是什么之前,我们先不说这个概念,先来看过程。
①先定义一个接口,里面包含方法--送礼物
public interface GiveGift { void giveGift(); }
②定义追求者的实体类,追求者A要实现送礼物给B的方法。
public class Pursuer implements GiveGift{ public void giveGift() { System.out.print("给B送礼物完成!"); } }
③定义代理类--我们的店员,要给完成追求者A送礼物给B的任务,店员知道这个礼物是谁让我送的,因此,要持有追求者的信息。
public class Proxy implements GiveGift { Pursuer gg; public Proxy(Pursuer gg) { this.gg = gg; } public void giveGift() { gg.giveGift(); } }
④送礼物过程:我是A,请帮我送礼物。
public static void main(String[] args){ Pursuer A = new Pursuer(); Proxy proxy = new Proxy(A); proxy.giveGift(); }
一整个故事看下来,静态代理的结构UML类图就明确了,如下图:
2、动态代理
我们今天要说的动态代理,仅仅说jdk的动态代理,不涉及cglib。
我们先来看一例,如何使用jdk的动态代理,要想使用,首先得看下代理类中有哪些方法可以用到。
在jdk的代理类Proxy中(package java.lang.reflect下),我们看下产生代理类的方法newProxyInstance:
有两种方式:
1、使用newProxyInstance方法
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
这里有三个参数,一个是ClassLoader类加载器,一个是interfaces一组接口类(因为一个类可以实现多个接口),InvocationHandler是回调内容处理器。
我们举一例,说明使用过程:
①定义接口类
package com.zhaodf.pattern; public interface GiveGift { void giveChocolate(String name); void giveFlower(String name); }
②定义接口实现类
package com.zhaodf.pattern; public class GiveGiftImpl implements GiveGift{ public void giveChocolate(String name) { System.out.println("送巧克力给B"); } public void giveFlower(String name) { System.out.println("送花给B"); } }
③定义回调方法处理器,这里我们仿照Mybatis的处理方法,分开处理Object类的方法和我们目标对象类的方法
package com.zhaodf.pattern; import org.apache.ibatis.reflection.ExceptionUtil; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class GiveGiftInvocationHandler implements InvocationHandler { //定义目标对象,最后使用反射要调用目标对象中的方法 //这里使用Object,所有对象都是Object的子类,这里就有了共性 private Object target; //提供构造函数,将目标对象持有 public GiveGiftInvocationHandler(Object target){ this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //这里我们可以仿照Mybatis中的写法,分开两部分 //一部分是Object中自有的方法,如toString,HashCode等 if (Object.class.equals(method.getDeclaringClass())) { try { System.out.println("调用Object类的方法"); return method.invoke(this, args); } catch (Throwable var5) { throw ExceptionUtil.unwrapThrowable(var5); } } else { Object result = method.invoke(target,args); return result; } } }
④使用JDK提供的代理类Proxy中newProxyInstance方法,动态生成代理类,调用对应方法:
package com.zhaodf.pattern; import java.lang.reflect.Proxy; public class TestProxy { public static void main(String[] args){ GiveGift giveGift = (GiveGift)Proxy.newProxyInstance( GiveGiftImpl.class.getClassLoader(), new Class[]{GiveGift.class}, new GiveGiftInvocationHandler(new GiveGiftImpl())); giveGift.giveChocolate("Angel"); giveGift.giveFlower("Angel"); giveGift.toString(); } }
⑤结果截图:
2、使用getProxyClass方法
其他内容一样,我们只修改TestProxy中的调用方法 。方法二与方法一不同的地方在于,方法二将步骤拆成了两步,其实源码中调用的生成代理类的方法是一样的,一会说到源码我们再说。
package com.zhaodf.pattern; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class TestProxy { public static void main(String[] args) throws Exception { //方法二 Class proxy0 = Proxy.getProxyClass(GiveGiftImpl.class.getClassLoader(), new Class[]{GiveGift.class}) ; Constructor constructor = proxy0.getConstructor(InvocationHandler.class); GiveGift giveGift2 = (GiveGift)constructor.newInstance(new GiveGiftInvocationHandler((new GiveGiftImpl()))); giveGift2.giveChocolate("Angel"); giveGift2.giveFlower("Angel"); giveGift2.toString(); } }
从静态代理和动态代理的使用过程我们可以解答上述问题了--为什么叫静态代理?
这是因为,在我们静态代理使用过程中,我们需要自己去写代理类Proxy,在代理类中调用实现类的方法,对于不同的代理对象,我们需要自己提供不同的代理类。
而动态代理中,使用了JDK提供的代理类Proxy,能够实现不同对象的代理,利用反射去调用实现类中的方法,更具有扩展性和一般性,在使用中我们可以根据需求使用JDK提供的代理类动态的生成我们的代理类对象。
因为,静态代理的静态体现在我们自己写的代理类,只能去满足当前一次性需求,因此叫静态。
而JDK提供的动态代理方式,则可以满足更多对象的代理请求,因此,动态代理也是具有一般性的一种设计模式。这也告诉我们,在日常需求涉及中,要从具体中抽象一般,达到多用,重用的目标。
二、动态代理的源码解析
在会使用,如果是我,我还想继续了解它的生成过程,这样可以知其然也知其所以然,理解的通透。
问自己几个问题:
- 代理类长啥样?在哪,我想看见它,内容是什么?
- 源码的调用过程,代理类是怎么生成的?
我们带着疑问去了解这些内容。首先要说明的是,我使用的jdk版本是1.8。
1、代理类长啥样?在哪?
既然是动态代理,那么如果我们没做任何操作,生成的代理类会通过类加载器被JVM直接被加载在内存中,我们是看不到的,因此,我们需要做些额外操作。这里提供两种方法:
①通过设置系统属性
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
public static void main(String[] args) throws Exception { //方法一 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); GiveGift giveGift = (GiveGift)Proxy.newProxyInstance( GiveGiftImpl.class.getClassLoader(), new Class[]{GiveGift.class}, new GiveGiftInvocationHandler(new GiveGiftImpl())); giveGift.giveChocolate("Angel"); giveGift.giveFlower("Angel"); giveGift.toString(); }
我们知道,System.getProperties()中的属性集是系统执行程序的全局属性。那为什么我们设置sun.misc.ProxyGenerator.saveGeneratedFiles为true就能将代理类文件保存下来呢?问的好!
设置了总得用了才能知道为什么这么设置,一会我们源码就会看到。
我们先来段(在ProxyClassFactory类的apply方法中,jdk版本是1.8):
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);
在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<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); } } }); } return var4; }
看到没,看if判断,在源码中会根据saveGeneratedFiles(是否保存生成的文件属性)来判断,如果为true,那么会将生成的文件内容保存在com\sun\proxy\$ProxyX(X表示数字)中。这里的WindowsPath是表示生成的路径是相对于你的Windows环境来说的。最后合起来的生成路径就是:E:\mybatis\com\sun\proxy。(因个人项目环境而已)
②直接使用ProxyGenerator类的方法
我们的测试方法中,使用JDK的动态代理类的Proxy.newProxyInstance方法,已经获取到了代理类,那么我们就可以将该代理类的字节码写到文件中,保存为class文件,这样也能看到具体的内容,我们看我们写的方法内容:
public static void main(String[] args) throws Exception { //方法一 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); GiveGift giveGift = (GiveGift)Proxy.newProxyInstance( GiveGiftImpl.class.getClassLoader(), new Class[]{GiveGift.class}, new GiveGiftInvocationHandler(new GiveGiftImpl())); giveGift.giveChocolate("Angel"); giveGift.giveFlower("Angel"); giveGift.toString(); byte[] proxyClass = ProxyGenerator.generateProxyClass(giveGift.getClass().getSimpleName(), giveGift.getClass().getInterfaces()); //将字节码文件保存到E盘,文件名为$Proxy1.class FileOutputStream outputStream = new FileOutputStream(new File("E:\\mybatis\\com\\zhaodf\\Proxy1.class")); outputStream.write(proxyClass); outputStream.flush(); outputStream.close(); }
生成的文件及目录如下图(这里的目录E:\\mybatis\\com\\zhaodf\\如果没有就需要手动新建):
按照上述两种方式,都可以获取到生成的代理类,那么内容是什么?当然,生成的class文件是字节码,我们可以使用工具看到字节码内容:
import com.zhaodf.pattern.GiveGift; 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 GiveGift { private static Method m1; private static Method m3; private static Method m2; private static Method m4; private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); } public final boolean equals(Object paramObject) throws { try { return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final void giveFlower(String paramString) throws { try { this.h.invoke(this, m3, new Object[] { paramString }); return; } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() throws { try { return ((String)this.h.invoke(this, m2, null)); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final void giveChocolate(String paramString) throws { try { this.h.invoke(this, m4, new Object[] { paramString }); return; } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() throws { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName("com.zhaodf.pattern.GiveGift").getMethod("giveFlower", new Class[] { Class.forName("java.lang.String") }); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m4 = Class.forName("com.zhaodf.pattern.GiveGift").getMethod("giveChocolate", new Class[] { Class.forName("java.lang.String") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } }
生成的代理类内容很简单,它继承了Proxy,实现了我们给定的接口GiveGift。
静态代码块中初始化了5个方法,分别是Object类的三个--equals、toString、hashCode(因为我们没有重写这三个方法,直接继承的就是Object类的),以及GiveGift接口中的两个方法giveChocolate和giveFlower。
每个方法的调用都是调用回调器类对象h中的invoke方法。
2、源码解析--代理类是如何生成的?
我们从Proxy.newProxyInstance说起。先来源码瞧一瞧:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); 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); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } 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); } }
我们一行一行来解释:
- final Class<?>[] intfs = interfaces.clone();将我们传入的接口类数组做了一个克隆
- Class<?> cl = getProxyClass0(loader, intfs);根据我们传进来的类加载器和克隆后的接口数组获取代理类,此部分我们单独作为一点重点讲。
- final Constructor<?> cons = cl.getConstructor(constructorParams);根据得到的代理类cl,调用它的构造函数,传入的参数是constructorParams,内容为Class<?>[] constructorParams = { InvocationHandler.class };也就是我们生成的代理类中的构造函数部分:
public $Proxy0(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); }
- final InvocationHandler ih = h;将我们传入的GiveGiftInvocationHandler对象h赋值给ih
- return cons.newInstance(new Object[]{h});使用GiveGiftInvocationHandler对象h构造代理类对象。
我们来详细解释Class<?> cl = getProxyClass0(loader, intfs);部分。
源码如下:
/** * Generate a proxy class. Must call the checkProxyAccess method * to perform permission checks before calling this. */ 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 ProxyClassFactory return proxyClassCache.get(loader, interfaces); }
- 这里有个限制条件if (interfaces.length > 65535),就是代理类实现的接口个数不能超过65535个(估计也没人这么傻),这里可以作为跟别人吹牛的一个条件。
- proxyClassCache.get(loader, interfaces);如果发现通过给定接口数组的类的加载器已经定义过代理类。那么直接返回缓存的副本,否则,需要通过代理类的工厂类去新创建一个代理类。这里我们重点看下。
在讲proxyClassCache.get(loader, interfaces);方法之前,我们先看下proxyClassCache是什么:
/** * a cache of proxy classes */ private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
proxyClassCache字面意思是代理类的缓存,它是WeakCache<ClassLoader, Class<?>[], Class<?>>的对象。我们看下WeakCache的构造函数:
/** * Construct an instance of {@code WeakCache} * * @param subKeyFactory a function mapping a pair of * {@code (key, parameter) -> sub-key} * @param valueFactory a function mapping a pair of * {@code (key, parameter) -> value} * @throws NullPointerException if {@code subKeyFactory} or * {@code valueFactory} is null. */ public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) { this.subKeyFactory = Objects.requireNonNull(subKeyFactory); this.valueFactory = Objects.requireNonNull(valueFactory); }
这里的K为ClassLoader,P为Class<?>[]接口数组,V为对应的代理类。
我们看proxyClassCache.get(loader, interfaces);源码部分:
public V get(K key, P parameter) { //参数检查不为空 Objects.requireNonNull(parameter); //清除掉缓存的cacheKey值 expungeStaleEntries(); Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (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 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; while (true) { 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 } 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); } } } }
我们详细解释下关键代码:
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
我们看下subKeyFactory.apply(key, parameter)的源码:
@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 { 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 in 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 = 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. */ 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()); } } }
这里就是代理类生成的关键地方了。我们关注下重点代码,这里传入的参数,一个是类加载器,一个是接口克隆数组。
在第一个for循环中,首先根据参数接口数组获取到全限定名的接口类,判断接口数组中的每个接口类是否存在,是否是接口,在第三个判断中,将接口类放到了IdentityHashMap中,如果已经在IdentityHashMap存在,那么说明接口数组中传递的接口类参数中有重复。
我们接着往下看,proxyPkg定义了最后生成的代理类放的包位置。
第二个for循环,验证所有的非non-public的接口在同一个包下。
因为上述步骤都没有成功设置proxyPkg,因此这里proxyPkg为null,那么将代理包位置设置为默认值:
这里获取代理类的名称,因为并发情况下可能会存在多个代理类,所以这里使用了原子类,保证唯一,因为我们是第一次生成,因此代理类的名称连同包名为:com.sun.proxy.$Proxy0
下面将正式进入代理类的生成过程:
/* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);
这里传递了三个参数,一是代理的类的名称com.sun.proxy.$Proxy0,一个是接口类数组,一个是类的访问标识(其实就是修饰符的数值)。
我们进去看下源码:
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<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); } } }); } return var4; }
在这个方法中完成了两个功能:
- final byte[] var4 = var3.generateClassFile();这个方法将生成代理类的内容,包含代理的方法,构造函数等,我们下面详细阐述。
- if (saveGeneratedFiles),根据saveGeneratedFiles属性值判断,如果为true,将生成的代理类字节码写到文件中,并放到对应的目录。
我们先来看第一个方法 var3.generateClassFile():
private byte[] generateClassFile() { //将Object的三个代理方法hashCode,equals,toString放在代理方法的map中 //Map<String, List<ProxyGenerator.ProxyMethod>> proxyMethods 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]; //循环遍历,将代理类中的接口方法也放到代理方法的map中 this.addProxyMethod(var8, var4); } } Iterator var11 = this.proxyMethods.values().iterator(); List var12; //循环校验代理方法Map中的方法返回类型是否合法 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); } } }
此方法中,完成的操作就是我们最后看到的代理类的字节码内容,包含属性,代理方法,代理类的构造函数等等。
代码过程图如下:
最后一步,将生成的代理类加载到内存中。
defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
三、综述
以上就是JDK代理设计模式的所有内容,看过此篇,对代理类的所有过程都没有疑问。
相关推荐
### Java设计模式详解——附有代码与图解 #### 一、设计模式概述 设计模式是一种在特定场景下解决问题的最佳实践。在软件工程领域,设计模式可以帮助开发人员编写出易于维护、扩展性强的代码。Java设计模式主要包括...
"java设计模式"这个文件可能包含了关于Java中设计模式的详细讨论,涵盖了各种模式的用途、优缺点以及如何在Java项目中有效地应用它们。你可能还会找到一些实用的代码示例,帮助你快速掌握这些模式。 总结来说,设计...
### Java设计模式详解 在软件开发领域,设计模式是一种被广泛认可且经验证有效的解决方案,它们可以帮助开发者解决在设计过程中遇到的各种常见问题。本篇文章将详细介绍几种常见的Java设计模式及其背后的原理,包括...
本篇文档将深入解析Java设计模式,并结合图表和代码示例进行详细讲解。 首先,我们来看创建型模式。这类模式主要关注对象的创建过程,减少类与类之间的耦合。 1.1 工厂方法模式:它定义了一个创建对象的接口,但让...
### Java设计模式之六大创建型模式详解 #### 引言 设计模式是在软件工程领域内,为了解决特定类型的问题而形成的解决方案模板。在《Java设计模式》中,重点介绍了六大创建型设计模式,这些模式提供了不同的方法来...
设计模式详解 设计模式是软件开发中的一种解决方案,旨在提高代码的可重用性、可维护性和可扩展性。在这篇文章中,我们将对23种常见的设计模式进行整理和解释。 1. Singleton 模式 Singleton 模式是一种创建型模式...
其中,"单一职责原则"(Single Responsibility Principle,SRP)是面向对象设计的基本原则之一,也是Java设计模式中的重要组成部分。本篇文章将深入探讨单一职责原则的概念、意义、应用及其在Java编程中的实际运用。...
### Java设计模式详解 #### 一、概述 Java设计模式是一种在特定上下文中解决软件设计问题的方案。设计模式能够帮助开发人员编写出更灵活、更易于维护的代码。本篇文档将详细介绍几种常见的Java设计模式,包括工厂...
《Java多线程编程实战指南》这本书深入浅出地讲解了Java多线程的核心概念和实战技巧,分为核心篇和设计模式篇,旨在帮助开发者掌握并应用多线程技术。 1. **线程基础** - **线程的创建**:Java提供了两种创建线程...
从给出的内容来看,这篇文章主要讨论了关于Java多线程设计模式的书籍,而这本书则由结城洛著作、博硕文化翻译。尽管用户在描述中提到,能找到的相关多线程书籍相对较少,并且对于这本由日本人著的书表示出一定的遗憾...
在Java编程中,"BUG模式"通常指的是程序员在编写代码时容易犯的一些常见错误或陷阱,这些错误可能导致程序运行不正常、性能下降甚至...《JAVA.BUG模式详解》这本书将深入讲解这些主题,帮助你成为更出色的Java程序员。
在网络上流畅很广的一篇旧文,暂时没找到原作者,目前所看到的最早转载时间是 2005 年 2 月 28 日。...(更新:已找到一篇发布时间是 2003 年 11 月20 日发布的文章,原标题是《追MM与设计模式(java的32种设计模式)》
在Java编程中,"Bug模式"是指在实践中常见的编程错误或陷阱,这些错误可能导致程序运行异常、性能下降或者...详细内容请参考提供的《Java.Bug模式详解.pdf》文档,深入学习和理解每个模式的成因、影响以及解决方案。
**代理模式**(Proxy模式)是一种结构型设计模式,它为另一个对象提供代理或占位符,以便控制对该对象的访问。 - **目的**:控制对某个对象的访问,通常用于实现更复杂的控制机制。 - **应用场景**: - 实现权限...
Java设计模式是软件工程中的一种最佳实践,它们是解决常见编程问题的经验总结,可以提高代码的可读性、可维护性和可扩展性。本篇主要关注的是创建型设计模式,这是设计模式中的一个重要类别,主要处理对象的创建过程...
- **设计模式**:设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。例如单例模式、工厂模式等。 - **性能优化**:包括内存管理、垃圾回收机制的理解以及避免内存泄漏等问题。 - **单元...
本篇将深入探讨一个名为“奥多停车小程序”的Java项目,该项目包含了完整的源码、项目部署视频和相关资料,旨在帮助学生理解和实践Java开发流程。 首先,我们要明确的是,这个项目的核心是开发一个停车管理应用。...
- **主要内容:** 这是设计模式领域的奠基之作。 - **涵盖知识点:** - 设计模式的定义 - 设计原则 - 创建型模式 - 结构型模式 - 行为型模式 - 模式的应用案例分析等。 #### 六、敏捷开发与测试驱动开发篇 ...