您当前的位置: 首页 > 

星夜孤帆

暂无认证

  • 4浏览

    0关注

    626博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

JDK&CGLIB动态代理源码解析

星夜孤帆 发布时间:2021-06-01 20:19:28 ,浏览量:4

一.代理模式 1.1.基本介绍

代理模式:一个对象提供一个替身,以控制对这个对象的访问。

即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。-

代理模式有不同的形式,主要有三种静态代理、动态代理(JDK 代理、接口代理)和CGLIB 代理(可以在内存动态的创建对象,而不需要实现接口,他是属于动态代理的范畴)。

1.2.静态代理 1.2.1.基本介绍

静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类。

 定义一个接口

public interface Teacher {
	void teach();
}

定义一个实现类 

public class JTeacher implements Teacher {

	// 实现具体的内容
	public void teach() {
		System.out.println("Jak正在讲解代理模式");

	}
}

定义代理类 

// 静态代理的方式
public class TeacherProxy implements Teacher{
	// 定义引用
	private Teacher teacher;

	//具体的目标对象传入进来
	public TeacherProxy(Teacher teacher) {
		this.teacher = teacher;
	}
	public void teach() {
		System.out.println("begin...");
		// 调用目标对象的方法
		teacher.teach();
		System.out.println("end...");
	}
}

使用代理前结果:

使用代理后结果:

成功通过静态代理,对目标方法进行了增强

上述是实现了一个接口,假如有多个接口呢?

代理类就会做很大的修改,很不容易扩展维护

再定义一个接口

public interface School {
	void work();
}

实现此接口 

public class JTeacher implements Teacher, School {
	// 实现具体的内容
	public void teach() {
		System.out.println("Jak正在讲解代理模式");

	}
	// 在工作
	public void work() {
		System.out.println("Jak在清华工作");
	}
}

代理类进行修改

/ 静态代理的方式
public class TeacherProxy implements Teacher, School{
	// 定义引用
	private Teacher teacher;
	private School school;

	//具体的目标对象传入进来
	public TeacherProxy(Teacher teacher, School school) {
		this.teacher = teacher;
		this.school = school;
	}
	public void teach() {
		System.out.println("begin...");
		// 调用目标对象的方法
		teacher.teach();
		System.out.println("end...");
	}
	public void work() {
		System.out.println("begin...");
		school.work();
		System.out.println("end...");
	}
}

1.3 JDK动态代理

jdk代理是基于接口的代理,所以被代理的对象必须是有接口实现的类,代理创建时通过Proxy.newProxyInstance实现的,这个方法有三个参数:

//指定要使用的类加载器
ClassLoader loader,
//被代理的类所实现的接口,增强接口的方法
Class[] interfaces,
//方法处理器,会拦截所有方法,然后执行增强参数。
InvocationHandler inoker

 定义一个类

public interface Teacher {
	void teach();
}

定义一个实现类 

public class JTeacher implements Teacher {
	// 实现具体的内容
	public void teach() {
		System.out.println("Jak正在讲解代理模式");

	}
}

定义一个生成代理的代理工厂

// 生成代理对象的工厂类
public class JdkProxyFactory implements InvocationHandler {
	// 定义目标对象引用
	private Object target;
	public void setTarget(Object target) {
		this.target = target;
	}
	// 提供方法,生成代理对象的
	public Object getProxy() {
		// 使用JDK的API方法
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("begin...");
		// 让目标对象的方法去执行,使用反射方式
		// 执行method
		Object result = method.invoke(target, args);
		System.out.println("end...");
		return result;
	}
}

测试结果:

再看一下动态代理,实现多个接口的情况

public class JTeacher implements Teacher, School {
	// 实现具体的内容
	public void teach() {
		System.out.println("Jak正在讲解代理模式");

	}
	// 在工作
	public void work() {
		System.out.println("Jak在清华工作");
	}
}

代理工厂不需要任何改动

// 生成代理对象的工厂类
public class JdkProxyFactory implements InvocationHandler {
	// 定义目标对象引用
	private Object target;
	public void setTarget(Object target) {
		this.target = target;
	}
	// 提供方法,生成代理对象的
	public Object getProxy() {
		// 使用JDK的API方法
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("begin...");
		// 让目标对象的方法去执行,使用反射方式
		// 执行method
		Object result = method.invoke(target, args);
		System.out.println("end...");
		return result;
	}
}

 测试结果

此时,我们的代理工厂代码就不用动,测试的时候,只需要School来接收,然后,调用相应的方法即可实现增强功能。这样以来,对我们程序的扩展就非常方便。

1.4 Cglib动态代理
public interface TargetInterface {

	String sayHello(String name);

	String sayThanks(String name);
}

 

public class TargetInterfaceImpl implements TargetInterface {

	public String sayHello(String name) {
		return "Hello, " + name;
	}

	public String sayThanks(String name) {
		return "Thanks, " + name;
	}
}

 

**
 * TargetProxy类还不是一个真正的代理类,它是代理类的一部分
 */
public class TargetProxy implements MethodInterceptor {
	// 获取真正的代理类
	public  T getProxy(Class clazz) {
		// 继承目标类,覆盖目标类的方法
		// 字节码增强的一个类
		Enhancer enhancer = new Enhancer();
		// 设置父类
		enhancer.setSuperclass(clazz);
		// 设置回调类,继承了MethodInterceptor,而它又继承了CallBack
		enhancer.setCallback(this);
		// 创建代理类
		return (T) enhancer.create();
	}

    /**
     * @param obj       CGLIB 生成的代理对象
     * @param method    被代理对象方法
     * @param args      方法入参
     * @param proxy     方法代理
     */
	// 即可以拦截sayHello,也可以拦截sayThanks
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println(method.getName() + "服务限流.......");
		// 调用目标方法(代理类是子类,目标类是父类)
		return proxy.invokeSuper(obj, args);
		/**
		// 获取一个接口的代理,那么需要在此对接口进行实现
		String hello = "Hello, " + args;
		return hello;
		 */
	}
}
public class Main {
	public static void main(String[] args) {
		// 通过参数设置,把动态代理生成的字节码.class文件输出到D盘
		System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:/");
		TargetProxy targetProxy = new TargetProxy();

		// 拿到目标类的代理类
		TargetInterfaceImpl targetInterface = targetProxy.getProxy(TargetInterfaceImpl.class);
		System.out.println(targetInterface.sayHello("jak"));
		System.out.println(targetInterface.sayThanks("jak"));
	}
}

完成了对目标方法的增强

二、源码解析 2.1 JDK动态代理源码

核心点:从源码-->编译好一个字节码文件.class-->类加载器变成对象-->构造器变成实例对象

类的加载机制、类加载详解

	// 提供方法,生成代理对象的
	public Object getProxy() {
		// 使用JDK的API方法
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}

对于上面这个方法,调用后就直接是一个对象了,对应流程图中,相当于已经到了实例对象User对象那步了,但是,前面的那些流程我们都没有做

肯定是Java替我们做了这些工作,那么它是怎么做的呢?

如果对反射创建对象不清楚的可以先看下这个:反射创建对象

// 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对象,相当于到了流程图的第二步了
        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() {
                    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

    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

 public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        ConcurrentMap valuesMap = map.get(cacheKey);
        // 第一次取肯定是没有的,进入判断
        if (valuesMap == null) {
            ConcurrentMap oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier stored by that
        // subKey from valuesMap
        // 如果没有,就在此处生成
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue 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);
                }
            }
        }
    }

// ProxyClassFactory in Proxy.apply

        @Override
        public Class apply(ClassLoader loader, Class[] interfaces) {

            Map 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数组中,正常情况,编译后生成一个.class文件存到磁盘
            // 这就是流程图的第一步
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                // native方法,通过类加载器,加载到内存,帮你生成Class对象
                // 流程图的第二步
                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

    public static byte[] generateProxyClass(final String name,
                                            Class[] interfaces,
                                            int accessFlags)
    {
        ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
        // 这里是生成 JDK 动态代理 Class File 的逻辑,暂时可以忽略。
        final byte[] classFile = gen.generateClassFile();
        // 如果 saveGeneratedFiles 变量为 true,把生成的 Class 文件写入到当前项目根目录下
        if (saveGeneratedFiles) {
            java.security.AccessController.doPrivileged(
            new java.security.PrivilegedAction() {
                public Void run() {
                    try {
                        int i = name.lastIndexOf('.');
                        Path path;
                        if (i > 0) {
                            Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
                            Files.createDirectories(dir);
                            path = dir.resolve(name.substring(i+1, name.length()) + ".class");
                        } else {
                            path = Paths.get(name + ".class");
                        }
                        Files.write(path, classFile);
                        return null;
                    } catch (IOException e) {
                        throw new InternalError(
                            "I/O exception saving generated file: " + e);
                    }
                }
            });
        }

        return classFile;
    }

讲到这你可能会说,还是不懂,刚才只是讲了你怎么生成的字节码文件,怎么生成的Class对象,但是它怎么执行的呢?

刚才说到,生成的.class字节码保存到了byte数组中,那么我们能不能把它保存成文件,看看到底做了什么呢?

如果可以的话,我们就可以通过生成的文件,把它反编译回来,看看它生成的源码长什么样

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

// $Proxy0这个代理类继承了Proxy实现了Teacher和School接口
public final class $Proxy0 extends Proxy implements Teacher, School {
    private static Method m1;
    private static Method m4;
    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);
        }
    }

    // 重写了work方法
    public final void work() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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);
        }
    }

    // 重写了teach方法
    public final void teach() 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"));
            m4 = Class.forName("com.best.staticProxy.School").getMethod("work");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.best.staticProxy.Teacher").getMethod("teach");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

 

参考JDK动态代理

2.2 CGLIB动态代理源码

CGLIB动态代理实现原理、参考CGLIB动态代理

上文中的是通过 enhancer.create 方法调用获取的代理对象,以此为入口深入探究一下 CGLIB 动态代理的实现原理。

// Enhancer#create

// 生成代理类名称是用到了 SOURCE 字段
private static final Source SOURCE = new Source(Enhancer.class.getName());

public Enhancer() {
    super(SOURCE);
}	

public Object create() {
    classOnly = false;
	argumentTypes = null;
	return createHelper();
}

// Enhancer#createHelper

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

// AbstractClassGenerator.create

	protected Object create(Object key) {
		try {
			ClassLoader loader = getClassLoader();
			Map cache = CACHE;
			ClassLoaderData data = cache.get(loader);
			if (data == null) {
				synchronized (AbstractClassGenerator.class) {
					cache = CACHE;
					data = cache.get(loader);
					if (data == null) {
						Map newCache = new WeakHashMap(cache);
						data = new ClassLoaderData(loader);
						newCache.put(loader, data);
						CACHE = newCache;
					}
				}
			}
			this.key = key;
            // 也就是ClassLoaderData的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);
		}
	}

接下来我们关注 ClassLoaderData 的 get 方法的逻辑。

// 代理类字节码的默认生成策略
private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE;

// 代理类的默认命名策略
private NamingPolicy namingPolicy = DefaultNamingPolicy.INSTANCE;

protected Class generate(ClassLoaderData data) {
  Class gen;
  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) {
      // 1. 生成代理类的类名
      String name = generateClassName(data.getUniqueNamePredicate());              
      data.reserveName(name);
      this.setClassName(name);
    }
    // 2. 生成代理类字节码的二进制数组
    byte[] b = strategy.generate(this);
    String className = ClassNameReader.getClassName(new ClassReader(b));
    ProtectionDomain protectionDomain = getProtectionDomain();
    synchronized (classLoader) { // just in case
      if (protectionDomain == null) {
        gen = ReflectUtils.defineClass(className, b, classLoader);
      } else {
        gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
      }
    }
    return gen;
}

private String generateClassName(Predicate nameTestPredicate) {
    return namingPolicy.getClassName(namePrefix, source.name, key, nameTestPredicate);
}

 CGLIB 通过 DefaultNamingPolicy 类中的 getClassName 方法获取到代理类的名称,逻辑如下所示

/**
 *  为代理类选择一个类名
 * @param prefix  被代理类的全路径名称,比如这里的 com.wilimm.proxy.cglib.Service
 * @param source  生成代理类的全限定名(如 "net.sf.cglib.Enhance", "net.sf.cglib.reflect.FastClass")
 * @param key    表示参数状态的关键对象; 要使缓存正常工作,相等的键应该生成相同的生成类名。默认策略将 key.hashCode() 合并到类名中。
 * @param names  如果给定的类名已经在同一个 ClassLoader 中使用,则返回 true 的谓词。
 * @return 全限定的代理类类名
 */
public String getClassName(String prefix, String source, Object key, Predicate names) {
  String base =
    prefix + "$$" + 
    source.substring(source.lastIndexOf('.') + 1) +
    getTag() + "$$" +
    Integer.toHexString(STRESS_HASH_CODE ? 0 : key.hashCode());
  String attempt = base;
  int index = 2;
  
  // 检测生成的代理类名是否已经生成,如果已经生成,则需要添加后缀
  while (names.evaluate(attempt))
    attempt = base + "_" + index++;
  return attempt;
}

protected String getTag() {
    return "ByCGLIB";
}

我们简单看一下 DefaultGeneratorStrategy 类中的 generate 方法,这是真正生成代理类的地方。 

public byte[] generate(ClassGenerator cg) throws Exception {
  DebuggingClassWriter cw = getClassVisitor();
  // 生成代理类的地方,代码逻辑过于复杂,暂时忽略
  transform(cg).generateClass(cw);
  return transform(cw.toByteArray());
}

最后,我们重点关注下 DebuggingClassWriter 类中的 toByteArray 方法,在这个方法中我们可以看到如何保存 CGLIB 代理类 Class 到文件中。

public static final String DEBUG_LOCATION_PROPERTY = "cglib.debugLocation";
    
private static String debugLocation;

static {
  debugLocation = System.getProperty(DEBUG_LOCATION_PROPERTY);
  if (debugLocation != null) {
    System.err.println("CGLIB debugging enabled, writing to '" + debugLocation + "'");
  }
}

public byte[] toByteArray() {
  return (byte[]) java.security.AccessController.doPrivileged(
  new java.security.PrivilegedAction() {
    public Object run() {
      byte[] b = ((ClassWriter) DebuggingClassWriter.super.cv).toByteArray();
      
      // 如果 DebuggingClassWriter.DEBUG_LOCATION_PROPERTY 系统属性被设置,则输出代理类到指定目录
      if (debugLocation != null) {
        String dirs = className.replace('.', File.separatorChar);
        try {
          new File(debugLocation + File.separatorChar + dirs).getParentFile().mkdirs();
          
          File file = new File(new File(debugLocation), dirs + ".class");
          OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
          try {
            out.write(b);
          } finally {
            out.close();
          }
        } catch (Exception e) {
          throw new CodeGenerationException(e);
        }
      }
      return b;
     }  
    });
  }
}
CGLIB 生成的代理类剖析

由上文可知,把 DebuggingClassWriter.DEBUG_LOCATION_PROPERTY(也就是 cglib.debugLocation)系统属性设置为当前项目的根目录,即可保存 CGLIB 生成的代理类到当前项目根目录下。

运行前文中 Client 的 main 方法,即可在当D盘看到 CGLIB 生成的代理类 Class 文件,如下图所示。

 

TargetInterfaceImpl$$EnhancerByCGLIB$$49b0b14d.class就是CGLIB生成的代理类,它继承了Service

public class TargetInterfaceImpl$$EnhancerByCGLIB$$49b0b14d extends TargetInterfaceImpl implements Factory {

    private MethodInterceptor CGLIB$CALLBACK_0; // 拦截器
    private static final Method CGLIB$publicMethod$0$Method; // 被代理方法
    private static final MethodProxy CGLIB$publicMethod$0$Proxy; // 代理方法

    static void CGLIB$STATICHOOK1() {
        // 代理类
        Class var0 = Class.forName("com.wilimm.proxy.cglib.Service$$EnhancerByCGLIB$$bdabbd96");
        // 被代理类
        Class var1;
        CGLIB$publicMethod$0$Method = ReflectUtils.findMethods(new String[]{"publicMethod", "()V"}, (var1 = Class.forName("com.wilimm.proxy.cglib.Service")).getDeclaredMethods())[0];
        CGLIB$publicMethod$0$Proxy = MethodProxy.create(var1, var0, "()V", "publicMethod", "CGLIB$publicMethod$0");
    }

    // 代理方法(methodProxy.invokeSuper会调用)
    final String CGLIB$sayThanks$0(String var1) {
        return super.sayThanks(var1);
    }

    // 被代理方法(methodProxy.invoke会调用,这就是为什么在拦截器中调用methodProxy.invoke会死循环,一直在调用拦截器)
    public final String sayThanks(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (this.CGLIB$CALLBACK_0 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$sayThanks$0$Method, new Object[]{var1}, CGLIB$sayThanks$0$Proxy) : super.sayThanks(var1);
    }

    final String CGLIB$sayHello$1(String var1) {
        return super.sayHello(var1);
    }

    public final String sayHello(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (this.CGLIB$CALLBACK_0 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$sayHello$1$Method, new Object[]{var1}, CGLIB$sayHello$1$Proxy) : super.sayHello(var1);
    }

}

MethodProxy 类非常关键,我们分析一下它的内部逻辑。

public class MethodProxy {
    private Signature sig1;
    private Signature sig2;
    private CreateInfo createInfo;
    
    private final Object initLock = new Object();
    private volatile FastClassInfo fastClassInfo;
    
    /**
     *
     * @param c1  被代理对象 Class
     * @param c2  CGLIB 代理对象 Class
     * @param desc 入参类型
     * @param name1 有拦截器逻辑的方法名 publicMethod
     * @param name2 直接调用父类方法的方法名 CGLIB$publicMethod$0
     * @return
     */
    public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
        MethodProxy proxy = new MethodProxy();
        proxy.sig1 = new Signature(name1, desc);
        proxy.sig2 = new Signature(name2, desc);
        proxy.createInfo = new CreateInfo(c1, c2);
        return proxy;
    }
    
    private void init() {
          CreateInfo ci = createInfo;
          FastClassInfo fci = new FastClassInfo();
          // 1. 生成被代理类 FastClass,在这里是 Service$$FastClassByCGLIB$$fdf36b96
          fci.f1 = helper(ci, ci.c1);
          // 2. 生成代理类 FastClass,在这里是 Service$$EnhancerByCGLIB$$bdabbd96$$FastClassByCGLIB$$a112cdb2
          fci.f2 = helper(ci, ci.c2);
          // 3. 得到被代理类 FastClass 中的 publicMethod 方法签名
          fci.i1 = fci.f1.getIndex(sig1);
          // 4. 得到代理类 FastClass 中的 CGLIB$publicMethod$0 方法签名
          fci.i2 = fci.f2.getIndex(sig2);
          fastClassInfo = fci;
          createInfo = null;
    }
    
    private static class FastClassInfo {
        FastClass f1; //被代理类 FastClass,在这里是 Service$$FastClassByCGLIB$$fdf36b96
        FastClass f2; //代理类 FastClass,在这里是 Service$$EnhancerByCGLIB$$bdabbd96$$FastClassByCGLIB$$a112cdb2
        int i1; // 被代理类 FastClass 中的 publicMethod方法签名(index)
        int i2; // 代理类 FastClass 中的 CGLIB$publicMethod$0 的方法签名
    }
    
    /**
     * 在相同类型的不同对象上调用原始方法。如果传入的是代理对象,则调用的是 CGLIB 代理类重写的方法     
     * @param obj 方法调用的对象,如果使用 MethodInterceptor 的 intercept 方法的第一个参数,将导致递归
     * @param args 参数列表
     */
    public Object invoke(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            // 调用 Service$$FastClassByCGLIB$$fdf36b96 类中的 publicMethod 方法
            return fci.f1.invoke(fci.i1, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (IllegalArgumentException e) {
            if (fastClassInfo.i1 < 0)
                throw new IllegalArgumentException("Protected method: " + sig1);
            throw e;
        }
    }

    /**
     * 在代理对象上调用父类的原始方法
     * @param obj CGLIB 生成的代理对象
     * @param args 参数列表
     */
    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            // 调用 Service$$EnhancerByCGLIB$$bdabbd96$$FastClassByCGLIB$$a112cdb2 类中的 CGLIB$publicMethod$0 方法
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }
}

FastClass 机制

package com.wilimm.proxy.cglib;

import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;

public class Service$$FastClassByCGLIB$$fdf36b96 extends FastClass {
    public Service$$FastClassByCGLIB$$fdf36b96(Class var1) {
        super(var1);
    }
    
    // 根据方法签名,获取到 FastClass 中的方法 index 值
    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -560613858:
            if (var10000.equals("finalMethod()V")) {
                return 1;
            }
            break;
        case -433379701:
            if (var10000.equals("publicMethod()V")) {
                return 0;
            }
            break;
        }

        return -1;
    }
    
     /**
     * 调用 FastClass 中的方法
     * @param var1 方法 index 值
     * @param var2 方法所在的类的对象
     * @param var3 参数列表
     */
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        // 强制转换 Object 为 Service 类型,从而可以直接调用 Service 中定义的方法
        Service var10000 = (Service)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                var10000.publicMethod();
                return null;
            case 1:
                var10000.finalMethod();
                return null;
            case 2:
                return new Boolean(var10000.equals(var3[0]));
            case 3:
                return var10000.toString();
            case 4:
                return new Integer(var10000.hashCode());
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
}

package com.wilimm.proxy.cglib;

import com.wilimm.proxy.cglib.Service..EnhancerByCGLIB..bdabbd96;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.reflect.FastClass;

public class Service$$EnhancerByCGLIB$$bdabbd96$$FastClassByCGLIB$$a112cdb2 extends FastClass {
    public Service$$EnhancerByCGLIB$$bdabbd96$$FastClassByCGLIB$$a112cdb2(Class var1) {
        super(var1);
    }
    
    // 根据方法签名,获取到 FastClass 中的方法 index 值  
    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -560613858:
            if (var10000.equals("finalMethod()V")) {
                return 21;
            }
            break;
        case -433379701:
            if (var10000.equals("publicMethod()V")) {
                return 9;
            }
            break;
        case 920107676:
            if (var10000.equals("CGLIB$publicMethod$0()V")) {
                return 16;
            }
            break;
        return -1;
    }

   /**
     * 调用 FastClass 中的方法
     * @param var1 方法 index 值
     * @param var2 方法所在的类的对象
     * @param var3 参数列表
     */
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        // 强制转换 Object 为 bdabbd96 代理类类型,从而可以直接调用 代理类中定义的方法
        bdabbd96 var10000 = (bdabbd96)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                return new Boolean(var10000.equals(var3[0]));
            case 1:
                return var10000.toString();
            case 2:
                return new Integer(var10000.hashCode());
            case 3:
                return var10000.clone();
            case 4:
                return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
            case 5:
                return var10000.newInstance((Callback[])var3[0]);
            case 6:
                return var10000.newInstance((Callback)var3[0]);
            case 7:
                var10000.setCallbacks((Callback[])var3[0]);
                return null;
            case 8:
                var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
                return null;
            case 9:
                var10000.publicMethod();
                return null;
            case 10:
                bdabbd96.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
                return null;
            case 11:
                bdabbd96.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
                return null;
            case 12:
                return var10000.getCallbacks();
            case 13:
                return var10000.getCallback(((Number)var3[0]).intValue());
            case 14:
                return bdabbd96.CGLIB$findMethodProxy((Signature)var3[0]);
            case 15:
                bdabbd96.CGLIB$STATICHOOK1();
                return null;
            case 16:
                var10000.CGLIB$publicMethod$0();
                return null;
            case 17:
                return var10000.CGLIB$clone$4();
            case 18:
                return new Integer(var10000.CGLIB$hashCode$3());
            case 19:
                return var10000.CGLIB$toString$2();
            case 20:
                return new Boolean(var10000.CGLIB$equals$1(var3[0]));
            case 21:
                var10000.finalMethod();
                return null;
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
}

CGLib 动态代理原理是什么?

CGLIB原理: 动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。

在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

CGLIB底层∶使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

三、CGLIB 和 JDK 动态代理区别

JDK动态代理是利用反射机制生成一个实现代理接口的类(这个类看不见摸不着,在jvm内存中有这个类),在调用具体方法前调用InvokeHandler来处理。

核心是实现InvocationHandler接口,使用invoke()方法进行面向切面的处理,调用相应的通知。

CGLIB动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

核心是实现MethodInterceptor接口,使用intercept()方法进行面向切面的处理,调用相应的通知。

1、如果目标对象实现了接口,默认情况下Spring会采用JDK的动态代理实现AOP

2、如果目标对象实现了接口,Spring也可以强制使用CGLIB实现AOP

3、如果目标对象没有实现接口,必须采用CGLIB实现动态代理,当然Spring可以在JDK动态代理和CGLIB动态代理之间转换 

CGLIB缺点: 对于final类和final方法,无法进行代理;

CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

(利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理>

性能区别

1.CGLib 底层采用ASM字节码生成框架 ,使用字节码技术生成代理类,在jdk6之前比使用Java反射效率要高。

唯一需要注意的是,CGLib不能对声明为final类和final方法进行代理,因为CGLIB 原理是动态生成被代理类的子类。

2、在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点

但是到jdk8的时候jdk代理效率高于CGLIB代理。 

各自局限 

1、JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理。

2、cglib他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

JDK Proxy 的优势 

最小化依赖关系,减少依赖意味着简化开发和维护,JDK本身的支持,可能比 cglib 更加可靠。

平滑进行JDK版本升级,而字节码类库通常需要进行更新以保证在新版Java 上能够使用。代码实现简单。

CGLIB的优势∶

从某种角度看,限定调用者实现接口是有些侵入性的实践,类似cglib动态代理就没有这种限制。只操作我们关心的类,而不必为其他相关类增加工作量。另外高性能。

参考博客、参考博客、参考博客、参考博客、视频教程

关注
打赏
1636984416
查看更多评论
立即登录/注册

微信扫码登录

0.1320s