jdk代理和cglib代理源代碼之我見
以前值是讀過一遍jdk和cglib的代理,時間長了,都忘記入口在哪裏了,值是記得其中的一些重點了,今天寫一篇博客,當作是筆記。和以前一樣,關鍵代碼,我會用紅色標記出來。
首先,先列出我的jdk代理對象和測試代碼:
package com.example.gof.proxy; /** * 買車接口 */ public interface BuyCard { void buycard(); }
package com.example.gof.proxy; import java.lang.reflect.InvocationHandler; importjava.lang.reflect.Method; public class BuyCardDynamicProxy implements InvocationHandler { private Object object; public BuyCardDynamicProxy(final Object object) { this.object = object; } /** * 代理回調的方法,反編譯後可以看到調用的是這段代碼:super.h.invoke(this, m3, null); * m3 = Class.forName("com.example.gof.proxy.BuyCard").getMethod("buycard", new Class[0]); *@param proxy 代理 * @param method 代理調用的而方法 * @param args 調用的方法的參數 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("動態代理,買車前"); Object res= method.invoke(object,args); System.out.println("動態代理,洗刷刷"); return res; } }
package com.example.gof.proxy; import com.example.gof.proxy.impl.BuyCardImpl; import sun.misc.ProxyGenerator; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.Proxy; public class TestBuyCardDynamicProxy { public static void main(String[] args) throws IOException { BuyCard buyCard = new BuyCardImpl(); BuyCard buyCardProxy = (BuyCard) Proxy.newProxyInstance(BuyCard.class.getClassLoader(), new Class[]{BuyCard.class}, new BuyCardDynamicProxy(buyCard)); buyCardProxy.buycard();
//下面這段是用於生成字節碼分析的 // byte[] classFile= ProxyGenerator.generateProxyClass("$Proxy", new Class<?>[]{BuyCard.class}); // File file=new File("D:\\java\\GoF\\src\\main\\java\\com\\example\\gof\\proxy/$Proxy.class"); // FileOutputStream os=new FileOutputStream(file); // os.write(classFile); // os.flush(); // os.close(); } }
跟蹤進去,查看 Proxy.newProxyInstance(BuyCard.class.getClassLoader() 這個方法,代碼如下:
/** * Returns an instance of a proxy class for the specified interfaces * that dispatches method invocations to the specified invocation * handler. * 返回一個代理類實例,用於調用響應的接口方法 * <p>{@code Proxy.newProxyInstance} throws * {@code IllegalArgumentException} for the same reasons that * {@code Proxy.getProxyClass} does. * * @param loader the class loader to define the proxy class * @param interfaces the list of interfaces for the proxy class * to implement * @param h the invocation handler to dispatch method invocations to * @return a proxy instance with the specified invocation handler of a * proxy class that is defined by the specified class loader * and that implements the specified interfaces * @throws IllegalArgumentException if any of the restrictions on the * parameters that may be passed to {@code getProxyClass} * are violated * @throws SecurityException if a security manager, <em>s</em>, is present * and any of the following conditions is met: * <ul> * <li> the given {@code loader} is {@code null} and * the caller‘s class loader is not {@code null} and the * invocation of {@link SecurityManager#checkPermission * s.checkPermission} with * {@code RuntimePermission("getClassLoader")} permission * denies access;</li> * <li> for each proxy interface, {@code intf}, * the caller‘s class loader is not the same as or an * ancestor of the class loader for {@code intf} and * invocation of {@link SecurityManager#checkPackageAccess * s.checkPackageAccess()} denies access to {@code intf};</li> * <li> any of the given proxy interfaces is non-public and the * caller class is not in the same {@linkplain Package runtime package} * as the non-public interface and the invocation of * {@link SecurityManager#checkPermission s.checkPermission} with * {@code ReflectPermission("newProxyInPackage.{package name}")} * permission denies access.</li> * </ul> * @throws NullPointerException if the {@code interfaces} array * argument or any of its elements are {@code null}, or * if the invocation handler, {@code h}, is * {@code null} */ @CallerSensitive 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); } }
/** * a cache of proxy classes */ private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); /** * 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); }
上面這個代碼當初看了很久,怎麽到proxyClassCache.get(loader, interfaces); 就已經生成了代理對象呢。後來百度下,才知道proxyClassCache9 這個對象調用構造參數時候,就生成了二進制文件,核心代碼也在這裏。繼續往下看
/** * 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 { 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 {
//加載到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()); } } }
繼續跟進生成二進制字節碼的方法:ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags)
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; }
由上面可以看見,核心代碼,就是生成了二進制字節碼文件Files.write(var2, var4, new OpenOption[0]);
為什麽我們看不見呢,那是因為被刪除了,可以手動生成這個二進制文件(.class後綴的),也就是上面的那段測試代碼的例子。
下面是二進制字節碼的文件內容:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // import com.example.gof.proxy.BuyCard; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy extends Proxy implements BuyCard { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public $Proxy(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { 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 void buycard() throws { try { super.h.invoke(this, m3, (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); } } 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.example.gof.proxy.BuyCard").getMethod("buycard"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
從上面可以看到,除了自定義的buycard() 方法外,還有toString()、equals()、hashCode() 三個方法。這三個方法是Object 的方法,每個接口、類都會從Object繼承這三個方法。當調用buycard()的時候,可以看到調用的是super.h.invoke(xxx) 這樣調用的。這裏的h,就是我們自定義的,繼承了InvocationHandler的類:BuyCardDynamicProxy。
至於invoke方式是怎麽調用的,在另外一篇博客https://www.cnblogs.com/drafire/p/9637349.html 繼續解析
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面看下cglib的代碼解讀,依然是先貼出測試代碼
public class BuyCardCglibProxy implements MethodInterceptor { private Object target; public Object getInstance(final Object target) { this.target = target; Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("cglib動態代理前"); //這裏使用的是methodProxy.invokeSuper,而不是method.invoke //代理類調用父類的方法 Object res= methodProxy.invokeSuper(o,objects); System.out.println("cglib動態代理後"); return res; } }
package com.example.gof.proxy; import com.example.gof.proxy.impl.BuyCardImpl; import org.springframework.cglib.core.DebuggingClassWriter; public class TestBuyCardCglibProxy { public static void main(String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, TestBuyCardCglibProxy.class.getClass().getResource("/").getPath() ); BuyCard buyCard=new BuyCardImpl(); BuyCardCglibProxy proxy=new BuyCardCglibProxy(); BuyCardImpl impl= (BuyCardImpl)proxy.getInstance(buyCard); impl.buycard(); } }
關鍵代碼在:enhancer.create() 這個方法,跟蹤進去,代碼如下:
public Object create() { this.classOnly = false; this.argumentTypes = null; return this.createHelper(); }
private Object createHelper() { this.preValidate(); Object key = KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter), this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID); this.currentKey = key; Object result = super.create(key); return result; }
protected Object create(Object key) { try { ClassLoader loader = this.getClassLoader(); //獲取加載器 Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> cache = CACHE;
//從緩存中讀取 AbstractClassGenerator.ClassLoaderData data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader); if (data == null) { //如果緩存沒有對應的數據 Class var5 = AbstractClassGenerator.class; synchronized(AbstractClassGenerator.class) { cache = CACHE; data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader); if (data == null) { Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> newCache = new WeakHashMap(cache); data = new AbstractClassGenerator.ClassLoaderData(loader); //生成二進制字節碼 newCache.put(loader, data); CACHE = newCache; } } } this.key = key; Object obj = data.get(this, this.getUseCache());
//生成代理對象 return obj instanceof Class ? this.firstInstance((Class)obj) : this.nextInstance(obj); } catch (RuntimeException var9) { throw var9; } catch (Error var10) { throw var10; } catch (Exception var11) { throw new CodeGenerationException(var11); } }
public ClassLoaderData(ClassLoader classLoader) { if (classLoader == null) { throw new IllegalArgumentException("classLoader == null is not yet supported"); } else { this.classLoader = new WeakReference(classLoader); Function<AbstractClassGenerator, Object> load = new Function<AbstractClassGenerator, Object>() { public Object apply(AbstractClassGenerator gen) { Class klass = gen.generate(ClassLoaderData.this); //核心代碼 return gen.wrapCachedClass(klass); } }; this.generatedClasses = new LoadingCache(GET_KEY, load); } }
protected Class generate(AbstractClassGenerator.ClassLoaderData data) { Object save = CURRENT.get(); CURRENT.set(this); Class var8; try { ClassLoader classLoader = data.getClassLoader(); if (classLoader == null) { throw new IllegalStateException("ClassLoader is null while trying to define class " + this.getClassName() + ". It seems that the loader has been expired from a weak reference somehow. Please file an issue at cglib‘s issue tracker."); } String className; synchronized(classLoader) { className = this.generateClassName(data.getUniqueNamePredicate()); data.reserveName(className); this.setClassName(className); } Class gen; if (this.attemptLoad) { try { gen = classLoader.loadClass(this.getClassName()); Class var25 = gen; return var25; } catch (ClassNotFoundException var20) { ; } } byte[] b = this.strategy.generate(this); //核心代碼 className = ClassNameReader.getClassName(new ClassReader(b)); ProtectionDomain protectionDomain = this.getProtectionDomain(); synchronized(classLoader) { if (protectionDomain == null) { gen = ReflectUtils.defineClass(className, b, classLoader); } else { gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain); } } var8 = gen; } catch (RuntimeException var21) { throw var21; } catch (Error var22) { throw var22; } catch (Exception var23) { throw new CodeGenerationException(var23); } finally { CURRENT.set(save); } return var8; }
//org\springframework\spring-core\5.0.8.RELEASE\spring-core-5.0.8.RELEASE.jar!\org\springframework\cglib\core\DefaultGeneratorStrategy.class
public byte[] generate(ClassGenerator cg) throws Exception { DebuggingClassWriter cw = this.getClassVisitor(); //從這裏的源代碼,可以看出,底層是使用asm包的 this.transform(cg).generateClass(cw); return this.transform(cw.toByteArray()); }
//org\springframework\spring-core\5.0.8.RELEASE\spring-core-5.0.8.RELEASE.jar!\org\springframework\cglib\core\KeyFactory.class public void generateClass(ClassVisitor v) { ClassEmitter ce = new ClassEmitter(v); Method newInstance = ReflectUtils.findNewInstance(this.keyInterface); if (!newInstance.getReturnType().equals(Object.class)) { throw new IllegalArgumentException("newInstance method must return Object"); } else { Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes()); ce.begin_class(46, 1, this.getClassName(), KeyFactory.KEY_FACTORY, new Type[]{Type.getType(this.keyInterface)}, "<generated>"); EmitUtils.null_constructor(ce); EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance)); int seed = 0; CodeEmitter e = ce.begin_method(1, TypeUtils.parseConstructor(parameterTypes), (Type[])null); e.load_this(); e.super_invoke_constructor(); e.load_this(); List<FieldTypeCustomizer> fieldTypeCustomizers = this.getCustomizers(FieldTypeCustomizer.class); int i; for(i = 0; i < parameterTypes.length; ++i) { Type parameterType = parameterTypes[i]; Type fieldType = parameterType; Iterator var11; FieldTypeCustomizer customizer; for(var11 = fieldTypeCustomizers.iterator(); var11.hasNext(); fieldType = customizer.getOutType(i, fieldType)) { customizer = (FieldTypeCustomizer)var11.next(); } seed += fieldType.hashCode(); ce.declare_field(18, this.getFieldName(i), fieldType, (Object)null); e.dup(); e.load_arg(i); var11 = fieldTypeCustomizers.iterator(); while(var11.hasNext()) { customizer = (FieldTypeCustomizer)var11.next(); customizer.customize(e, i, parameterType); } e.putfield(this.getFieldName(i)); } e.return_value(); e.end_method(); e = ce.begin_method(1, KeyFactory.HASH_CODE, (Type[])null); i = this.constant != 0 ? this.constant : KeyFactory.PRIMES[Math.abs(seed) % KeyFactory.PRIMES.length]; int hm = this.multiplier != 0 ? this.multiplier : KeyFactory.PRIMES[Math.abs(seed * 13) % KeyFactory.PRIMES.length]; e.push(i); for(int i = 0; i < parameterTypes.length; ++i) { e.load_this(); e.getfield(this.getFieldName(i)); EmitUtils.hash_code(e, parameterTypes[i], hm, this.customizers); } e.return_value(); e.end_method(); e = ce.begin_method(1, KeyFactory.EQUALS, (Type[])null); Label fail = e.make_label(); e.load_arg(0); e.instance_of_this(); e.if_jump(153, fail); int i; for(i = 0; i < parameterTypes.length; ++i) { e.load_this(); e.getfield(this.getFieldName(i)); e.load_arg(0); e.checkcast_this(); e.getfield(this.getFieldName(i)); EmitUtils.not_equals(e, parameterTypes[i], fail, this.customizers); } e.push(1); e.return_value(); e.mark(fail); e.push(0); e.return_value(); e.end_method(); e = ce.begin_method(1, KeyFactory.TO_STRING, (Type[])null); e.new_instance(Constants.TYPE_STRING_BUFFER); e.dup(); e.invoke_constructor(Constants.TYPE_STRING_BUFFER); for(i = 0; i < parameterTypes.length; ++i) { if (i > 0) { e.push(", "); e.invoke_virtual(Constants.TYPE_STRING_BUFFER, KeyFactory.APPEND_STRING); } e.load_this(); e.getfield(this.getFieldName(i)); EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, this.customizers); } e.invoke_virtual(Constants.TYPE_STRING_BUFFER, KeyFactory.TO_STRING); e.return_value(); e.end_method(); ce.end_class(); } }
jdk代理和cglib代理源代碼之我見