源码角度深入理解JDK代理与CGLIB代理

 2023-02-02
原文作者:_沸羊羊_ 原文地址:https://juejin.cn/post/6997982790046351391

前言

本文将从源码角度分析 JDK 代理与 CGLIB 代理的原理与区别,如需要,可以点赞收藏。

动态代理的实现方式

常见的动态代理的实现方式有两种,一种是 JDK 的动态代理,一种是 CGLIB 动态代理。

JDK 动态代理 是Java自带的使用反射技术生成了一个实现代理接口的匿名类,在执行具体方法前调用 InvokeHandler 进行处理。JDK代理只能代理实现了接口的目标类,如果目标类没有实现的接口,则不能使用 JDK 代理。因为生成的代理类会继承 Proxy 父类,因为 Java 不支持多继承,所以只能通过实现目标类实现的接口的方式生成代理类。

CGLIB 动态代理 是使用ASM开源包,将代理对象类的 class 文件加载进来,然后利用字节码技术修改 class文件的字节码生成子类,进而实现代理类。cglib 代理不局限于接口,代理类采用的是生成子类的方式,只要被代理的类不被 final 修饰即可。

JDK

demo

IUserService & UserService

    public interface IUserService {
        void login();
    }
    
    public class UserService implements IUserService {
        @Override
        public void login() {
            System.out.println("UserSerivce 实现类");
        }
    }

ProxyUserService

    public class ProxyUserService {
    
        private IUserService userService;
    
        public ProxyUserService(IUserService userService) {
            this.userService = userService;
        }
    
        public Object proxyInstance() {
            return Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                    System.out.println("jdk proxy before");
                    Object invoke = method.invoke(userService, objects);
                    System.out.println("jdk proxy after");
                    return invoke;
                }
            });
        }
    }

Client

    public class Client {
        public static void main(String[] args) {
            // 保存生成的代理类的字节码文件
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    
            IUserService userService = new UserService();
            IUserService proxyUserService = (IUserService) new ProxyUserService(userService).proxyInstance();
            proxyUserService.login();
        }
    }

源码实现

newProxyInstance()
    @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.
          */
         // 使用自定义的InvocationHandler作为参数,调用构造函数获取代理类对象实例
         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);
         }
     }

进入到 getProxyClass0(loader, intfs);

    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
        // 如果缓存中存在相应接口的代理类直接返回,否则,使用 ProxyClassFactory 创建代理类
        return proxyClassCache.get(loader, interfaces);
    }

进入到 proxyClassCache.get(loader, interfaces);

    public V get(K key, P parameter) {
       ......
       // 如缓存中没有代理类,则调用 ProxyClassFactory 创建代理类
       Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
       ......
    }

ProxyClassFactory 类是 Proxy 的静态内部类。进入到 ProxyClassFactory 的 apply 方法

    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // 代理类类名前缀
        private static final String proxyClassNamePrefix = "$Proxy";
    
        // 生成代理类名称的计数器
        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");
    	        }
    	        
    	        // 校验该类是否是接口类型
    	        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");
    	            }
    	        }
    	    }
    		// public 接口使用指定包名
    	    if (proxyPkg == null) {
    	        // if no non-public proxy interfaces, use com.sun.proxy package
    	        proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
    	    }
    	    // 为代理类生成类名
    	    long num = nextUniqueNumber.getAndIncrement();
    	    String proxyName = proxyPkg + proxyClassNamePrefix + num;
    	
    	    // 生成代理类字节码文件
    	    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
    	        proxyName, interfaces, accessFlags);
    	    try {
    	    	// 将代理类的字节码文件加载到JVM中
    	        return defineClass0(loader, proxyName,
    	                            proxyClassFile, 0, proxyClassFile.length);
    	    } catch (ClassFormatError e) {
    	        throw new IllegalArgumentException(e.toString());
    	    }
    	}
    }

进入到生成字节码文件的方法 ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);该类未开源,可以使用 IDE 反编译后查看。

    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;
     }
代理对象字节码文件

我们来看一下生成的代理类经过反编译的字节码文件中都有什么

    public final class $Proxy0 extends Proxy implements IUserService {
        private static Method m1;
        private static Method m2;
        private static Method m3;
        private static Method m0;
    
        public $Proxy0(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 login() 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.dmsd.proxy.jdk.IUserService").getMethod("login");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }

可以看到生成的代理类的字节码文件中包含了以下内容:

  • 代理类继承了 Proxy 并且实现了目标类的实现的接口
  • 重写了 equals() , hashcode() , toString()
  • 静态代码块中,通过反射获取了需要重写和调用的方法
  • 使用父类的InvocationHandler 对象的 invoke 执行目标类中的目标方法 login()

CGLIB

ASM

ASM是一种通用Java字节码操作和分析框架,它可以用于修改现有的 class 文件或动态生成 class 文件。CGLIB 就是使用的 ASM框架 来增强目标类的字节码生成代理类的。

ASM 相关 API 在 spring-core.jar中的 org.springframework.asm 包下。

demo

UserService

    public class UserService {
        public void login() {
            System.out.println("UserSerivce 实现类");
        }
    }

MyIntercepter

```java public class MyIntercepter implements MethodInterceptor { /** * o: cglib 生成的代理对象 * method: 被代理的目标方法 * objects: 方法入参 * methodProxy: 代理方法 */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("cglib proxy before..."); Object obj = methodProxy.invokeSuper(o, objects); System.out.println("cglib proxy after..."); return obj; } } ```

Client

    public class Client {
        public static void main(String[] args) {
            // 保存生成的代理类的字节码文件
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./proxyByCglib");
            // 通过 cglib 动态代理获取代理对象
            Enhancer enhancer = new Enhancer();
            // 设置enhancer的父类
            enhancer.setSuperclass(UserService.class);
            // 设置 enhancer 的回调对象
            enhancer.setCallback(new MyIntercepter());
            // 创建代理对象
            UserService proxyUserService = (UserService) enhancer.create();
            // 通过代理对象调用目标方法
            proxyUserService.login();
        }
    }

源码分析

使用 cglib 代理必须自定义 Interceptor 实现 MethodInterceptor (方法拦截器)接口,源码如下:

    public interface MethodInterceptor extends Callback
    {
        /**
         * All generated proxied methods call this method instead of the original method.
         * The original method may either be invoked by normal reflection using the Method object,
         * or by using the MethodProxy (faster).
         * @param obj "this", the enhanced object
         * @param method intercepted Method
         * @param args argument array; primitive types are wrapped
         * @param proxy used to invoke super (non-intercepted method); may be called
         * as many times as needed
         * @throws Throwable any exception may be thrown; if so, super method will not be invoked
         * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
         * @see MethodProxy
         */    
        public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                                   MethodProxy proxy) throws Throwable;
     
    }

MethodInterceptor 接口只有一个 intercept(…)方法,其中的参数:

  • obj:代理对象
  • method:被拦截的方法,目标方法
  • args:表示要被拦截方法的参数
  • proxy:触发父类的方法对象

首先创建 Enhancer 对象,设置超类 Superclass 和自定义的回调对象 Callback,然后调用父类 AbstractClassGenerator 的 create() 方法生成超类的子类。

    public class Enhancer extends AbstractClassGenerator {
    	public Object create() {
    		classOnly = false;
    		argumentTypes = null;
    		return createHelper();
    	}
    }

进到 createHelper();

    private Object createHelper() {
    	// 校验 callbackTypes、filter
    	preValidate();
    	// 创建 EnhancerKey对象
    	Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
    			ReflectUtils.getNames(interfaces),
    			filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
    			callbackTypes,
    			useFactory,
    			interceptDuringConstruction,
    			serialVersionUID);
    	this.currentKey = key;
    	// 调用父类方法创建
    	Object result = super.create(key);
    	return result;
    }

进入到 Enhancer 的父类 AbstractClassGenerator 的create()

    protected Object create(Object key) {
    	try {
    		// 获取当前类加载器,应用类加载器
    		ClassLoader loader = getClassLoader();
    		Map<ClassLoader, ClassLoaderData> cache = CACHE;
    		// 缓存中获取类加载器数据
    		ClassLoaderData data = cache.get(loader);
    		if (data == null) {
    			// 同步锁锁住类
    			synchronized (AbstractClassGenerator.class) {
    				cache = CACHE;
    				data = cache.get(loader);
    				if (data == null) {
    					Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
    					data = new ClassLoaderData(loader);
    					// 将类加载器放到新缓存中
    					newCache.put(loader, data);
    					CACHE = newCache;
    				}
    			}
    		}
    		this.key = key;
    		// 调用 get方法获取字节码,如果没有字节码,则会创建字节码
    		Object obj = data.get(this, getUseCache());
    		if (obj instanceof Class) {
    			// 使用反射机制创建代理类对象
    			return firstInstance((Class) obj);
    		}
    		return nextInstance(obj);
    	}
    	catch (RuntimeException | Error ex) {
    		throw ex;
    	}
    	catch (Exception ex) {
    		throw new CodeGenerationException(ex);
    	}
    }

进入到 AbstractClassGenerator 的 get(this, getUseCache());

    public Object get(AbstractClassGenerator gen, boolean useCache) {
    	// 判断是否开启缓存
    	if (!useCache) {
    		// 生成字节码
    		return gen.generate(ClassLoaderData.this);
    	}
    	else {
    		Object cachedValue = generatedClasses.get(gen);
    		return gen.unwrapCachedValue(cachedValue);
    	}
    }

进入到generate(ClassLoaderData.this);

    protected Class generate(ClassLoaderData data) {
    	Class gen;
    	Object save = CURRENT.get();
    	CURRENT.set(this);
    	try {
    		ClassLoader classLoader = data.getClassLoader();
    		if (classLoader == null) {
    			throw new IllegalStateException("ClassLoader is null while trying to define class " +
    					getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " +
    					"Please file an issue at cglib's issue tracker.");
    		}
    		synchronized (classLoader) {
    			// 生成代理类名称
    			String name = generateClassName(data.getUniqueNamePredicate());
    			data.reserveName(name);
    			this.setClassName(name);
    		}
    		// 使用类加载器尝试加载,如果加载不到,才开始创建字节码
    		if (attemptLoad) {
    			try {
    				gen = classLoader.loadClass(getClassName());
    				return gen;
    			}
    			catch (ClassNotFoundException e) {
    				// ignore
    			}
    		}
    		// 通过指定策略生成字节码
    		byte[] b = strategy.generate(this);
    		String className = ClassNameReader.getClassName(new ClassReader(b));
    		ProtectionDomain protectionDomain = getProtectionDomain();
    		synchronized (classLoader) { // just in case
    			// 将字节码加载到JVm,生成代理类
    			gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain, contextClass);
    			// SPRING PATCH END
    		}
    		return gen;
    	}
    	catch (RuntimeException | Error ex) {
    		throw ex;
    	}
    	catch (Exception ex) {
    		throw new CodeGenerationException(ex);
    	}
    	finally {
    		CURRENT.set(save);
    	}
    }

进入 DefaultGeneratorStrategy 的 generate() 方法

    public byte[] generate(ClassGenerator cg) throws Exception {
        DebuggingClassWriter cw = this.getClassVisitor();
        this.transform(cg).generateClass(cw);
        return this.transform(cw.toByteArray());
    }

进入到 DebuggingClassWriter 的 toByteArray()

    public byte[] toByteArray() {
         return (byte[])((byte[])AccessController.doPrivileged(new PrivilegedAction() {
             public Object run() {
                 byte[] b = ((ClassWriter)DebuggingClassWriter.access$001(DebuggingClassWriter.this)).toByteArray();
                 if (DebuggingClassWriter.debugLocation != null) {
                     String dirs = DebuggingClassWriter.this.className.replace('.', File.separatorChar);
    
    			     // asm 技术生成 class 文件
                     try {
                         (new File(DebuggingClassWriter.debugLocation + File.separatorChar + dirs)).getParentFile().mkdirs();
                         File file = new File(new File(DebuggingClassWriter.debugLocation), dirs + ".class");
                         BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
    
                         try {
                             out.write(b);
                         } finally {
                             out.close();
                         }
                         if (DebuggingClassWriter.traceCtor != null) {
                             file = new File(new File(DebuggingClassWriter.debugLocation), dirs + ".asm");
                             out = new BufferedOutputStream(new FileOutputStream(file));
    
                             try {
                                 ClassReader cr = new ClassReader(b);
                                 PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
                                 ClassVisitor tcv = (ClassVisitor)DebuggingClassWriter.traceCtor.newInstance(null, pw);
                                 cr.accept(tcv, 0);
                                 pw.flush();
                             } finally {
                                 out.close();
                             }
                         }
                     } catch (Exception var17) {
                         throw new CodeGenerationException(var17);
                     }
                 }
    
                 return b;
             }
         }));
     }

上述 AbstractClassGenerator 的 create() 方法生成的代理类如果是 Class 类型,就调用 firstInstance((Class) obj);方法使用反射机制根据指定类生成代理对象;而 create() 方法生成的代理类如果不是 Class 类型,则调用 Enhancer 类的 nextInstance(obj);

    protected Object nextInstance(Object instance) {
    	EnhancerFactoryData data = (EnhancerFactoryData) instance;
    
    	if (classOnly) {
    		return data.generatedClass;
    	}
    
    	Class[] argumentTypes = this.argumentTypes;
    	Object[] arguments = this.arguments;
    	if (argumentTypes == null) {
    		argumentTypes = Constants.EMPTY_CLASS_ARRAY;
    		arguments = null;
    	}
    	// 创建代理对象实例
    	return data.newInstance(argumentTypes, arguments, callbacks);
    }

进入到 newInstance(argumentTypes, arguments, callbacks);
参数为:

  • 代理对象的构造参数类型数组
  • 代理对象的构造参数数组
  • 回调对象数组
    public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
    	// 设置线程回调
    	setThreadCallbacks(callbacks);
    	try {
    		// Explicit reference equality is added here just in case Arrays.equals does not have one
    		if (primaryConstructorArgTypes == argumentTypes ||
    				Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
    			// 通过反射机制生成代理对象
    			return ReflectUtils.newInstance(primaryConstructor, arguments);
    		}
    		return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
    	}
    	finally {
    		setThreadCallbacks(null);
    	}
    }

进入到反射的newInstance 方法

    public static Object newInstance(final Constructor cstruct, final Object[] args) {
    	// 获取安全访问标识
    	boolean flag = cstruct.isAccessible();
    	try {
    		if (!flag) {
    			cstruct.setAccessible(true);
    		}
    		// 反射创建代理对象实例
    		Object result = cstruct.newInstance(args);
    		return result;
    	}
    	// cath ......
    	finally {
    		if (!flag) {
    			cstruct.setAccessible(flag);
    		}
    	}
    }

字节码文件

202301012132483971.png

代理类字节码文件

将其中的 UserService

EnhancerByCGLIBEnhancerByCGLIB

4d8d88b5.class 字节码文件反编译后如下:

    public class UserService$$EnhancerByCGLIB$$4d8d88b5 extends UserService implements Factory {
        private boolean CGLIB$BOUND;
        public static Object CGLIB$FACTORY_DATA;
        private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
        private static final Callback[] CGLIB$STATIC_CALLBACKS;
        private MethodInterceptor CGLIB$CALLBACK_0;
        private static Object CGLIB$CALLBACK_FILTER;
        private static final Method CGLIB$login$0$Method;
        private static final MethodProxy CGLIB$login$0$Proxy;
        private static final Object[] CGLIB$emptyArgs;
        private static final Method CGLIB$equals$1$Method;
        private static final MethodProxy CGLIB$equals$1$Proxy;
        private static final Method CGLIB$toString$2$Method;
        private static final MethodProxy CGLIB$toString$2$Proxy;
        private static final Method CGLIB$hashCode$3$Method;
        private static final MethodProxy CGLIB$hashCode$3$Proxy;
        private static final Method CGLIB$clone$4$Method;
        private static final MethodProxy CGLIB$clone$4$Proxy;
    
    	// 静态代码块,反射创建代理方法
        static void CGLIB$STATICHOOK1() {
            CGLIB$THREAD_CALLBACKS = new ThreadLocal();
            CGLIB$emptyArgs = new Object[0];
            Class var0 = Class.forName("com.dmsd.proxy.cglib.UserService$$EnhancerByCGLIB$$4d8d88b5");
            Class var1;
            CGLIB$login$0$Method = ReflectUtils.findMethods(new String[]{"login", "()V"}, (var1 = Class.forName("com.dmsd.proxy.cglib.UserService")).getDeclaredMethods())[0];
            CGLIB$login$0$Proxy = MethodProxy.create(var1, var0, "()V", "login", "CGLIB$login$0");
            Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
            CGLIB$equals$1$Method = var10000[0];
            CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
            CGLIB$toString$2$Method = var10000[1];
            CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
            CGLIB$hashCode$3$Method = var10000[2];
            CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
            CGLIB$clone$4$Method = var10000[3];
            CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        }
    
        // 执行methodProxy.invokeSuper(o, objects);时会调用
        final void CGLIB$login$0() {
            super.login();
        }
       	// 核心方法
        public final void login() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
            	// 调用拦截器
                var10000.intercept(this, CGLIB$login$0$Method, CGLIB$emptyArgs, CGLIB$login$0$Proxy);
            } else {
                super.login();
            }
        }
    
        final boolean CGLIB$equals$1(Object var1) {
            return super.equals(var1);
        }
    
        public final boolean equals(Object var1) {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
                return var2 == null ? false : (Boolean)var2;
            } else {
                return super.equals(var1);
            }
        }
    
        final String CGLIB$toString$2() {
            return super.toString();
        }
    
        public final String toString() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
        }
    
        final int CGLIB$hashCode$3() {
            return super.hashCode();
        }
    
        public final int hashCode() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
                return var1 == null ? 0 : ((Number)var1).intValue();
            } else {
                return super.hashCode();
            }
        }
    
        final Object CGLIB$clone$4() throws CloneNotSupportedException {
            return super.clone();
        }
    
        protected final Object clone() throws CloneNotSupportedException {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
        }
    
        public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
            String var10000 = var0.toString();
            switch(var10000.hashCode()) {
            case -508378822:
                if (var10000.equals("clone()Ljava/lang/Object;")) {
                    return CGLIB$clone$4$Proxy;
                }
                break;
            case 1826985398:
                if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                    return CGLIB$equals$1$Proxy;
                }
                break;
            case 1913648695:
                if (var10000.equals("toString()Ljava/lang/String;")) {
                    return CGLIB$toString$2$Proxy;
                }
                break;
            case 1984935277:
                if (var10000.equals("hashCode()I")) {
                    return CGLIB$hashCode$3$Proxy;
                }
                break;
            case 2022705004:
                if (var10000.equals("login()V")) {
                    return CGLIB$login$0$Proxy;
                }
            }
    
            return null;
        }
    
        public UserService$$EnhancerByCGLIB$$4d8d88b5() {
            CGLIB$BIND_CALLBACKS(this);
        }
    
        public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
            CGLIB$THREAD_CALLBACKS.set(var0);
        }
    
        public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
            CGLIB$STATIC_CALLBACKS = var0;
        }
    
        private static final void CGLIB$BIND_CALLBACKS(Object var0) {
            UserService$$EnhancerByCGLIB$$4d8d88b5 var1 = (UserService$$EnhancerByCGLIB$$4d8d88b5)var0;
            if (!var1.CGLIB$BOUND) {
                var1.CGLIB$BOUND = true;
                Object var10000 = CGLIB$THREAD_CALLBACKS.get();
                if (var10000 == null) {
                    var10000 = CGLIB$STATIC_CALLBACKS;
                    if (var10000 == null) {
                        return;
                    }
                }
    
                var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
            }
    
        }
    
        public Object newInstance(Callback[] var1) {
            CGLIB$SET_THREAD_CALLBACKS(var1);
            UserService$$EnhancerByCGLIB$$4d8d88b5 var10000 = new UserService$$EnhancerByCGLIB$$4d8d88b5();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        }
    
        public Object newInstance(Callback var1) {
            CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
            UserService$$EnhancerByCGLIB$$4d8d88b5 var10000 = new UserService$$EnhancerByCGLIB$$4d8d88b5();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        }
    
        public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
            CGLIB$SET_THREAD_CALLBACKS(var3);
            UserService$$EnhancerByCGLIB$$4d8d88b5 var10000 = new UserService$$EnhancerByCGLIB$$4d8d88b5;
            switch(var1.length) {
            case 0:
                var10000.<init>();
                CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
                return var10000;
            default:
                throw new IllegalArgumentException("Constructor not found");
            }
        }
    
        public Callback getCallback(int var1) {
            CGLIB$BIND_CALLBACKS(this);
            MethodInterceptor var10000;
            switch(var1) {
            case 0:
                var10000 = this.CGLIB$CALLBACK_0;
                break;
            default:
                var10000 = null;
            }
    
            return var10000;
        }
    
        public void setCallback(int var1, Callback var2) {
            switch(var1) {
            case 0:
                this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
            default:
            }
        }
    
        public Callback[] getCallbacks() {
            CGLIB$BIND_CALLBACKS(this);
            return new Callback[]{this.CGLIB$CALLBACK_0};
        }
    
        public void setCallbacks(Callback[] var1) {
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
        }
    
        static {
            CGLIB$STATICHOOK1();
        }
    }

上述静态代码块会在JVM类加载此字节码文件时初始化此代理类,主要用于创建代理方法。

从生成的代理类反编译源码来看,可以得知:

  • 代理类继承自目标类 UserService
  • 拦截器调用 intercept(),由于自定义 MethodInterceptor 的实现 MyIntercepter ,所以直接调用我们自定义类中重写的 intercept() 方法,从而完成了由代理对象访问到目标对象的动态代理实现。
索引类字节码文件

从文件命名上来看,两个文件名都有 FastClass ,并且两个类都继承了 FastClass 类,代表这两个文件是索引文件,cglib 在方法调用时并没有使用反射,而是通过给每个代理类方法分配索引,通过 索引 来直接查找具体方法,类似于方法调用,这样比反射调用经过本地方法,效率高的多。

UserService

EnhancerByCGLIBEnhancerByCGLIB

4d8d88b5

FastClassByCGLIBFastClassByCGLIB

aaec18ff.class 文件部分内容如下:

    public class UserService$$EnhancerByCGLIB$$4d8d88b5$$FastClassByCGLIB$$aaec18ff extends FastClass {
        public UserService$$EnhancerByCGLIB$$4d8d88b5$$FastClassByCGLIB$$aaec18ff(Class var1) {
            super(var1);
        }
       public int getIndex(Signature var1) {
            String var10000 = var1.toString();
            switch(var10000.hashCode()) {
            case -2035807581:
                if (var10000.equals("CGLIB$login$0()V")) {
                    return 19;
                }
                break;
            case -1882565338:
                if (var10000.equals("CGLIB$equals$1(Ljava/lang/Object;)Z")) {
                    return 18;
                }
                break;
            case -1870561232:
                if (var10000.equals("CGLIB$findMethodProxy(Lorg/springframework/cglib/core/Signature;)Lorg/springframework/cglib/proxy/MethodProxy;")) {
                    return 13;
                }
                break;
            ......
            }
    
            return -1;
        } 
    }

我们看看执行过程是什么样的。

1、客户端使用代理对象调用目标方法

    UserService proxyUserService = (UserService) enhancer.create();
    proxyUserService.login();

此时,JVM会调用生成代理类的字节码文件 UserService

EnhancerByCGLIBEnhancerByCGLIB

4d8d88b5.class 中的 login()

    public final void login() {
       MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
    
        if (var10000 != null) {
        	// 回调, 调用拦截器
            var10000.intercept(this, CGLIB$login$0$Method, CGLIB$emptyArgs, CGLIB$login$0$Proxy);
        } else {
            super.login();
        }
    }

2、调用拦截器

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib proxy before...");
        Object obj = methodProxy.invokeSuper(o, objects);
        System.out.println("cglib proxy after...");
        return obj;
    }

跟进 invokeSuper(o, objects)

    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
    try {
    	init();
    		FastClassInfo fci = fastClassInfo;
    		return fci.f2.invoke(fci.i2, obj, args);
    	}
    	catch (InvocationTargetException e) {
    		throw e.getTargetException();
    	}
    }

3、找到方法对应索引

上述 init() 会进行方法索引绑定,调用的方法的索引为 16

202301012132491242.png

获取完方法索引传入到 invoke 方法,跟进 fci.f2.invoke(fci.i2, obj, args);

其中:

  • fci:封装了两个索引文件的 MethodProxy 的内部静态类FastClassInfo
  • f2:代理类的文件索引类
  • i2:表示具体方法索引

fci.f2.invoke(fci.i2, obj, args); 调用的是索引文件中的方法,通过索引 16,找到具体执行的方法是:

    case 16:
          var10000.CGLIB$login$0();
          return null;

4、执行目标方法

找到 索引 16 对应的代理类中的方法,就是目标类的方法。

    final void CGLIB$login$0() {
        super.login();
    }

JDK与CGLIB对比

JDK

特点:

  • 目标类必须实现接口
  • 使用反射生成代理对象

CGLIB

CGLIB 代理执行过程:调用目标方法 —> 执行目标方法的回调: 拦截器 —> 找到目标方法对应的索引 —> 找到索引对应目标方法并执行

特点:

  • 目标类不需要实现接口,但不能用 final 修饰
  • CGLIB 调用目标方法采用的是索引(类似于方法调用)的方式,比反射调用效率高

早期版本的 JDK 代理效率远远小于 CGLIB,但随着 jdk 的不断迭代优化,但 Spring 的 CGLIB 却止步不前,可以得知,较新版本的(JDK7及以后)JDK 代理的整体效率要高于 CGLIB代理。但 CGLIB 调用目标方法的性能要优于JDK使用反射调用方法的性能。