阅读 53

设计模式-代理模式(从源码角度去剖析JDK动态代理和CGLIB动态代理)

代理模式

代理模式分为静态代理和动态代理

静态代理简单易于理解,然而在实际工作中却不常用,其中的原因主要是:

  • 当需要代理多个类时,由于代理对象和目标对象接口一致,如果只维护一个代理类,该类就需要实现多个接口,导致代理类过于庞大
  • 当代理类的功能需要进行扩展或改动时,需要在代理类和目标对象中同时修改,不易维护

而动态代理具有广泛的应用,例如Spring AOP、RPC远程调用、Java注解对象获取、日志、用户鉴权、全局异常处理以及性能监控等...

因此接下来就对Java中常见的两种动态代理进行分析:JDK原生动态代理和CGLIB动态代理

1 动态代理

动态代理就是给某一个对象提供一个代理对象,并由代理对象来控制对真实对象的访问,代理对象是一种结构性设计模式

动态代理的源码是在程序运行期间由JVM根据反射等机制动态生成,也就是在运行前并不存在代理类的字节码文件

1.1 代理模式涉及角色

  • Subject(抽象主题角色)

    定义代理类和真实主题的公开对外方法,也是代理类代理真实主题的方法

  • RealSubject(真实主题角色)

    真正实现业务逻辑的类

  • Proxy(代理主题角色)

    用来代理和封装真实主题

image-20210322170240376

1.2 动态生成原理

我们知道JVM类加载过程主要分为五个阶段:加载、验证、准备、解析以及初始化,其中加载阶段需要完成三件事情:

  • 通过一个类的全限定名来获取定义该类的二进制字节流
  • 将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构
  • 在内存中生成一个代表这个类的Class对象,作为方法区这个类的各种数据访问入口

实际上JVM规范对这3点要求并不具体,因此实际的实现非常灵活,例如获取类的二进制字节流(class字节码)存在多种途径:

  • 从ZIP包获取,这是JAR、EAR、WAR等格式的基础
  • 从网络中获取,典型的应用是 Applet
  • 运行时计算生成,这种场景使用最多的就是动态代理技术;在java.lang.reflect.Proxy类中就是使用ProxyGenerator.generateProxyClass来为特定接口生成形式为*$Proxy的代理类二进制字节流
  • 由其它文件生成,典型应用是JSP,即由JSP文件生成对应的Class类
  • 从数据库中获取等等

从而我们得出一个结论:动态代理就是根据接口或目标对象,计算出代理类的字节码,然后加载到JVM中使用

当然这里也引出一些问题:如何进行计算?如何生成字节码文件?,情况比我们想象中的复杂,因此我们直接借助现有方案

为了让生成的代理类和目标对象(真实主题角色)保持一致,下面介绍两种常见多的方式:

  • 通过实现接口->JDK动态代理
  • 通过继承类的方式->CGLIB动态代理

1.3 JDK动态代理

JDK动态代理主要涉及两个类:java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler

1.3.1 测试JDK动态代理

下面首先通过一个案例先做初步了解:

编写一个调用逻辑处理器LogHandler类提供日志增强功能,并实现InvocationHandler接口,在LogHandler类中维护一个目标对象,该对象是被代理的对象(真实主题角色)

被代理类

public interface UserService {
    void select();

    void update();
}

public class UserServiceImpl implements UserService{
    @Override
    public void select() {
        System.out.println("select by id");
    }

    @Override
    public void update() {
        System.out.println("update by id");
    }
}
复制代码

日志增强器

@Slf4j
public class LogHandler implements InvocationHandler {

    private Object target;

    public LogHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doBefore();
        // target(目标对象)调用目标方法
        Object res = method.invoke(target, args);
        doAfter();
        return res;
    }

    /**
     * 目标方法执行之前
     */
    private void doBefore() {
        log.info("log start time:{}",new Date());
    }

    /**
     * 目标方法执行之后
     */
    private void doAfter() {
        log.info("log end time:{}",new Date());
    }
}
复制代码

invoke()方法中的参数method实际上就是通过反射获取被代理对象执行的Method对象,而参数args就是执行方法时传入的参数值;而proxy实际上就是生成的代理对象实例

由于在LogHandler类中维护的target属性就是被代理对象,从而这里method.invoke(target, args)就是通过反射让被代理对象调用对应的方法获取结果

客户端

public class Client {
    public static void main(String[] args) {
        // 设置将动态生成的class保存为文件	      					                     System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        // 创建被代理对象
        UserServiceImpl userService = new UserServiceImpl();
        // 获取类加载器
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // 获取所有的接口class
        Class<?>[] interfaces = userService.getClass().getInterfaces();
        // 创建一个即将传给代理类的调用请求处理器,处理被代理对象的所有方法调用
        LogHandler logHandler = new LogHandler(userService);
        /**
         * 根据上面提供的信息创建代理对象的过程中:
         * 1、JDK会通过传入的参数信息动态地在内存中创建和.class文件等同的字节码
         * 2、然后根据响应的字节码转换成对应的class
         * 3、然后调用newInstance()创建代理实例
         */
        UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, logHandler);
        // 调用代理方法
        proxy.select();
        proxy.update();
    }
}
复制代码

刚才已经说过了logHandler的作用,而通过Proxy#newProxyInstance方法指定类加载器(需要加载生成的字节码文件)、所有实现的接口(以便生成的代理类具有和被代理类有相同的操作)以及logHandler生成了代理实例

测试结果

image-20210323101146242

小结

对于java.lang.reflect.InvocationHandler(调用处理器)

Object invoke(Object proxy, Method method, Object[] args) 方法就是定义了代理对象调用被代理对象的method希望执行的动作

对于java.lang.reflect.Proxy

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法就是构造一个实现指定接口的代理类新实例,而代理类实例调用方法时都会使用调用处理器的指定逻辑

1.3.2 代理类的调用过程

上面我们知道代理类对象是动态生成的,那么生成的代理类到底是什么样子呢?下面我们引入一个工具类来保存代理类

工具类

public class ProxyUtil {
    /**
     * 根据类信息动态生成的字节码保存到磁盘中,默认在clazz目录下
     *  params: clazz 需要生成动态代理类的类
     *  proxyName: 为动态生成的代理类的名称
     */
    public static void generateClassFile(Class clazz,String proxyName) {
        // 根据类信息和提供的代理类名称,生成字节码
        byte[] bytes = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
        String path = clazz.getResource(".").getPath();
        System.out.println(path);
        FileOutputStream fos = null;
        try {
            // 保存到硬盘
            fos = new FileOutputStream(path + proxyName + ".class");
            fos.write(bytes);
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert fos != null;
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
复制代码

这里首先就是通过ProxyGenerator#generateProxyClass获取clazz类的代理类字节码

然后获取项目的根路径,最后就是通过IO流保存到本地文件

修改客户端-生成代理文件

@Slf4j
public class Client {
    public static void main(String[] args) {
        ...		
        /**
         * 根据上面提供的信息创建代理对象的过程中:
         * 1、JDK会通过传入的参数信息动态地在内存中创建和.class文件等同的字节码
         * 2、然后根据响应的字节码转换成对应的class
         * 3、然后调用newInstance()创建代理实例
         */
        UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, logHandler);
        System.out.println(proxy);
        log.info("{}",proxy);
        // 调用代理方法
        proxy.select();
        proxy.update();

        ProxyUtil.generateClassFile(userService.getClass(),"UserServiceProxy");
    }
}
复制代码

相对于之前主要是通过工具类生成了代理类的class文件

测试结果

public final class UserServiceProxy extends Proxy implements UserService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
    private static Method m4;

    public UserServiceProxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
       ...
    }

    public final String toString() throws  {
    	...
    }

    public final void select() 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  {
      ...
    }

    public final void update() throws  {
        try {
            super.h.invoke(this, m4, (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("org.jiang.proxy.jdkproxy.UserService").getMethod("select");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m4 = Class.forName("org.jiang.proxy.jdkproxy.UserService").getMethod("update");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
复制代码

UserServiceProxy中可以发现:

  • UserServiceProxy继承了Proxy类,并且实现了被代理的所有接口,且重写了equals、hashCode、toString等方法

  • 由于UserServiceProxy继承了Proxy类,所以每个代理类都会关联一个InvocationHandler方法调用处理器(因为Proxy类内部维护了一个处理器对象)

    image-20210323110141583

  • 类和所有方法都被finial修饰,故代理类只能被使用,而不能被继承

  • 每个方法都有一个Method对象进行描述,Method对象在静态代码块中创建,以m+数字的格式命名

  • 调用方法的时候通过super.h.invoke(this, m3, (Object[])null)进行调用,而其中h实际上就是方法处理器,那么h.invoke()实际上就是我们通过Proxy#newProxyInstance传入的InvocationHandler对象来进行实际的处理逻辑调用

总结

实际上代理类在生成过程中就是将被代理类的所有方法转化为一个个Method对象,由于代理类继承于Proxy类,等同于代理类内部也维护了一个InvocationHandler对象,而这个对象就是在我们调用Proxy#newInstance方法时传递进来

进而当调用被代理类的方法时,实际上就是转化为通过InvocationHandler对象调用invoke()方法对指定的Mthod进行调用

image-20210323110956018

1.3.3 JDK代理源码分析

下面就通过上面分析的小案例debug进行分析:


首先我们定位到Proxy#newProxyInstance方法生成代理对象:

image-20210323112231368

当执行完这两步之后我们先来看下代理对象的class对象:

image-20210323112703915

代理类的名称为com.sun.proxy.$Proxy0,这个类是JVM运行时动态生成的,且以$开头,Proxy在中间,最后的序号表示类对象的序号

而且有一个公共构造器:

public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler),可以看出代理对象就是通过该构造器生成,且构造器传入的参数就是调用处理器


下面就具体对Proxy#newProxyInstance方法进行分析

    /** parameter types of a proxy class constructor */
    private static final Class<?>[] constructorParams =
        { InvocationHandler.class };

    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);  //h 不能为空,所以 InvocationHandler 是必须的

        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.
         * 调用这个代理类的构造器,传入指定的 invocation handler 对象
         */
        try {
            if (sm != null) {  //权限校验,不细讲
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            // 获取参数是 InvocationHander.class 类型的构造器
            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);
        }
    }
复制代码

1、检验调用处理器是否为空,然后通过对象拷贝所有的接口到intfs变量

2、接着就是调用Class<?> cl = getProxyClass0(loader, intfs)寻找或生成代理类,这一部分将会在1.3.3.1进行分析

3、开始执行时将变量constructorParams赋值为InvocationHandler的class对象,而这里就是通过反射创建代理类参数类型为InvocationHandler的有参构造器

4、设置构造器的访问权限,然后将参数中的h(也就是我们调用Proxy.newInstance()传入的对象)传入构造器中创建真正的代理类对象并返回


1.3.3.1 Proxy#getProxyClass0
private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    
    /**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
    
    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);
}
复制代码

一开始先判断被代理类实现的接口是否超过了65535,如果超过就直接抛出异常

然后调用proxyClassCache.get()生成代理类,从注释上也可以看出:

  • 如果代理类已经有指定的类加载器且继承了这些接口,那么将直接返回生成的代理类
  • 否则就由ProxyClassFactory生成代理类

我们这里大致的看下WeakCache#get方法:

image-20210323121431789


我们从上面知道创建类的核心就是在ProxyClassFactory类中

    /**
     * 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 
        //(所有生成的代理类前缀都是 $Proxy)
        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);

            // 遍历接口数组,校验:
            // 1)接口是否能找到,加载到的实例是否和传入的接口实例一样
            // 2)校验加载的实例是否是一个接口
            // 3)接口去重
            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.
             * 生成类的字节码,然后通过本地方法 defineClass0 生成代理类
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }
复制代码

首先类中声明了两个常量,一个用来代表生成代理类class对象的前缀,另外一个生成代理类的序号(类型为AtomicLong,线程安全)

类中只有一个apply()方法,明显就是用来生成代理类class对象,下面就只需要对该方法进行分析

  • 创建一个和代理类实现的所有接口个数一样的IdentityHashMapmap集合

  • 遍历被代理类实现的所有接口,通过Class.forName()寻找和遍历元素名称一致的class对象

  • 接着判断遍历的元素和通过类加载器寻找的class对象是否一致

  • 如果一切判断没有问题,就将该接口放入集合中作为key,而Boolean.TRUE作为value

  • 声明两个变量分别代表代理类的包路径和访问修饰符

  • 再次对所有的接口遍历,找出不是public修饰的接口元素,获取该元素的包名并设置给代理类的包名

  • 通过之前我们说过的代理类的前缀和序号(常量)生成代理类类名

  • 调用ProxyGenerator.generateProxyClass()生成代理类字节码数组

  • 代用本地方法defineClass0()生成代理类class对象

总结

这里说明一下,其实对ProxyClassFactory的分析和我们之前的测试也相呼应:

我们之前在编写ProxyUtil工具类时也是通过ProxyGenerator.generateProxyClass()方法生成代理类字节码byte数组

而在ProxyClassFactory类中也是通过该方法生成代理类字节码byte数组

进而通过向Proxy类中的InvocationHandler属性赋值来实现代理类调用被代理对象的方法切入

1.3.3.2 标记

其实这里我们可以得到一个结论:

  • 真正生成代理类的过程和被代理类并没有任何关系,只是说获取了被代理类的所有接口传入ProxyGenerator.generateProxyClass()
  • 这就说明我们只要指定一些接口和类加载器就可以生成代理类的class对象
  • 从而又说明一件事,当自定义InvocationHandler时类中的invoke()方法中并不是一定要涉及到被代理类的具体逻辑(一般需要),因为我们会利用生成代理类的class对象利用反射创建构造器并传入我们定义的InvocationHandler
  • 而生成的代理类class文件我们也很清楚,接口中的每个方法实际上委托给InvocationHandler调用invoke()方法

1.4 Cglib动态代理

我们知道JDK动态代理是基于接口的方式,也就是说代理类和目标类都实现同一个接口

而Cglib动态代理是代理类继承目标类,进而重写目标类的方法,从而保证代理类拥有目标类的同命方法

Cglib就是通过代理类继承目标类,每次调用代理类的方法被方法拦截器拦截,在拦截器中才是调用目标类该方法的真正逻辑

image-20210323123844199

1.4.1 测试Cglib

导入依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.5</version>
</dependency>
复制代码

被代理类

public class UserDao {
    public void select() {
        System.out.println("UserDao 查询 selectById");
    }
    public void update() {
        System.out.println("UserDao 更新 update");
    }
}
复制代码

方法拦截器(回调函数)

public class CustomerLogInterceptor implements MethodInterceptor {

    /**
     *
     * @param o 表示要增强的对象
     * @param method 拦截的方法
     * @param objects 表示方法的参数列表,基本数据类型需要传入其包装类型,如int-->Integer、long-Long、double-->Double
     * @param methodProxy 表示对方法的代理,invokeSuper方法表示对被代理对象的方法调用
     * @return 代理对象
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        // 注意这里是调用 invokeSuper 而不是 invoke,否则死循环,methodProxy.invokeSuper执行的是原始类的方法,method.invoke执行的是子类的方法
        Object result = methodProxy.invokeSuper(o, objects);
        after();
        return result;
    }

    private void before() {
        System.out.println(String.format("log start time [%s] ", new Date()));
    }
    private void after() {
        System.out.println(String.format("log end time [%s] ", new Date()));
    }
}
复制代码

测试类

public class CglibTest {
    public static void main(String[] args) {
        // 在指定目录下生成动态代理类
 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,CglibTest.class.getClassLoader().getResource(".").getPath());
        // 创建enhance对象,类似有JDK动态代理的proxy
        Enhancer enhancer = new Enhancer();
        // 设置目标类的字节码文件
        enhancer.setSuperclass(UserDao.class);
        // 设置回调函数
        enhancer.setCallback(new CustomerLogInterceptor());
        // 创建代理类对象
        UserDao user = (UserDao) enhancer.create();
        // 方法调用
        user.select();
    }
}
复制代码

测试结果

image-20210323143306121

这里看出不仅对被代理对象进行了代理,而且生成了代理类的class文件;下面我们就对这些具体过程进行分析

1.4.2 生成动态代理类

我们上面已经在指定目录生成了字节码文件,这里面实际有三个class文件:

  • 代理类的FastClass
  • 代理类
  • 目标类的FastClass

image-20210323143649762


代理类Class文件分析

public class UserDao$$EnhancerByCGLIB$$5c5103ea extends UserDao implements Factory {
    // 标识拦截器是否已经绑定
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    // 下面的两个变量用来保存回调类,也就是我们设置所有的拦截器,CGLIB会将回调先设置到这两个变量上,然后再进行绑定
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    // 这就是我们的拦截器,因为只添加了一个CallBack,所以这里只有一个
    // CGLIB可以添加多个CallBack
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    // 下面的所有Method都是被代理类的原始的Method
    private static final Method CGLIB$update$0$Method;
    // MethodProxy与FastClass机制有关
    private static final MethodProxy CGLIB$update$0$Proxy;
    // 空参数,一个默认值,当我们的方法没有参数的时候会传递给拦截器
    // 不传递空值,这是一种设置思想
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$select$1$Method;
    private static final MethodProxy CGLIB$select$1$Proxy;
    ...
     // 该方法会在静态代码块中被调用,对上面的变量进行初始化
     static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("org.jiang.proxy.cglib.UserDao$$EnhancerByCGLIB$$5c5103ea");
        Class var1;
        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$2$Method = var10000[0];
         var10000 = ReflectUtils.findMethods(new String[]{"update", "()V", "select", "()V"}, (var1 = Class.forName("org.jiang.proxy.cglib.UserDao")).getDeclaredMethods());
        CGLIB$update$0$Method = var10000[0];
        // 创建MethodProxy,每一个方法都会创建一个对应的MethodProxy
        // 当前代理会会为其所有父类的方法都创建对应的MethodProxy
        CGLIB$update$0$Proxy = MethodProxy.create(var1, var0, "()V", "update", "CGLIB$update$0");
        CGLIB$select$1$Method = var10000[1];
        CGLIB$select$1$Proxy = MethodProxy.create(var1, var0, "()V", "select", "CGLIB$select$1");
    }
    
    /**
	 * 用来调用父类的原始方法
	 * CGLIB生成代理利用的是继承,而不是JDK动态代理的利用接口的形式
	 * 这样就有一个区别就出现了,JDK动态代理中必须要有一个被代理类的实例
	 * 但是CGLIB实现的动态代理就不需要,因为是继承,所以就包含了被代理类的全部方法
	 * 但是我们调用生成的代理类实例的update()方法时,调用的就是CGLIB代理时候的方法
	 * 如果调用被代理类的原始方法呢,就是靠下面的这个方法
	 * CGLIB生成的代理类中每个原始方法都会有这两种类型的方法
	 */
    final void CGLIB$update$0() {
        super.update();
    }
    
    /**
	 * 生成的代理方法,在该方法中会调用我们设置的Callback
	 * 当调用代理类的update方法时,先判断是否已经存在实现了MethodInterceptor接口的拦截对象
	 * 如果没有的话就调用CGLIB$BIND_CALLBACKS方法来获取Callback
	 */
    public final void update() {
        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$update$0$Method, CGLIB$emptyArgs, CGLIB$update$0$Proxy);
        } else {
            super.update();
        }
    }
    
    /**
	 * CGLIB$BIND_CALLBACKS 先从CGLIB$THREAD_CALLBACKS(一个ThreadLocal对象)中getCallback
	 * 如果获取不到的话,再从CGLIB$STATIC_CALLBACKS来获取,如果也没有则认为该方法不需要代理。
     * 那么CallBack是如何设置到CGLIB$THREAD_CALLBACKS 或者 CGLIB$STATIC_CALLBACKS中的呢?
     * 在Jdk动态代理中拦截对象是在实例化代理类时由构造函数传入的
	     * 在cglib中我们使用Enhancers生成代理类时。是调用Enhancer的firstInstance方法来生成代理类实例并设置回调。
     * firstInstance的调用轨迹为:
		   1.Enhancer:firstInstance
		   2.Enhancer:createUsingReflection
		   3.Enhancer:setThreadCallbacks
		   4.Enhancer:setCallbacksHelper
		   5.Target$$EnhancerByCGLIB$$788444a0 : CGLIB$SET_THREAD_CALLBACKS
	 * 最终CGLIB实例化代理对象的时候,就在这里将所有的Callback成功设置了
	 */
    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        UserDao$$EnhancerByCGLIB$$5c5103ea var1 = (UserDao$$EnhancerByCGLIB$$5c5103ea)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];
        }

    }
复制代码

这里由于代码量过大,就简单贴出一些关键部分

从上面可以看出:

1、代理类继承于目标类,代理类为目标类中没有privatefinal修饰的每个方法生成两个方法(这是显而易见的,因为代理类是目标类的子类,代理目标方法如果通过这两种修饰符修饰就无法重写)

image-20210323145731466

对于update()方法这里有一个final修饰重写的update方法,以及CGLIB$update$0方法

对于CGLIB$update$0方法实际上就是调用父类的update()方法,也就等同于被代理类的目标方法


这里说明了一点,也就是在上面案例的拦截器中当调用methodProxy.invokeSuper(o, objects)方法时这里调用的也就是被代理类的方法,如果调用invoke()方法也就是代理类重写的方法

image-20210323150528308


2、从上面的分析也说明了另外一个问题,当我们生成代理类之后通过代理对象调用目标方法时调用的是代理类重写的方法

image-20210323150744038

下面就先对代理类重写的方法进行分析(以update方法为例):

1.1 首先判断类中是否已经存在MethodInterceptor对象,如果不存在,就调用CGLIB$BIND_CALLBACKS(this)方法

image-20210323152132143

这里就是先缓存一份this对象,然后判断是否可以换存ThreadLocal对象中获取到拦截器,如果不能就直接获取类中的拦截器数组,如果还是不能那就表示该方法不需要代理

image-20210323152335058

1.2 设置完拦截器之后,判断拦截器是否为空,如果为空则直接调用被代理对象的目标方法;如果不为空,则通过拦截器调用intercept()方法

image-20210323152858933

1.3 到这里我们就已经很熟悉了,因为我们在Enhancer对象中设置了拦截器,那么这里就会调用我们设置好的拦截器的intercept()方法

image-20210323153022406


这里还需要注意一点,就是代理类中存在一个静态代码块,在静态代码块中执行了重要的方法:

static {
    CGLIB$STATICHOOK1();
}

static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("org.jiang.proxy.cglib.UserDao$$EnhancerByCGLIB$$5c5103ea");
        Class var1;
    	CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
        ...
    }
复制代码

我们在前面提到过,CGLIB$STATICHOOK1()方法就是对一系列的变量进行初始化;而静态代码块中调用该方法也就意味着类一旦加载就会对各种变量进行初始化

而在CGLIB$STATICHOOK1()方法中执行了MethodProxy.create()方法,实际上就是为被代理类所有的方法都生成了对应的MethodProxy对象,每个方法对应的MethodProxy对象在执行MethodInterceptor.intercept()方法(该方法就是我们定义的每个拦截器对象拦截方法)中都会作为参数传递进去

image-20210323164747481

传递进去之后,就可以利用MethodProxy的方法使用FastClass机制:

/**
 * 一个MethodProxy对象,包含了两个方法的名称,一个是被代理类中的原始方法
 * 另外一个则是代理类中生成的用来调用被代理类原始方法的方法名
 * 当执行MethodProxy.invoke()方法时,其实就是用的被代理类的方法索引
 * 当执行MethodProxy.invokeSuper()方法时,用的是代理类中的方法的索引
 * 
 * c1是代理类实现的父类的class
 * c2是代理类的class
 * name1是被代理类中的原始方法名
 * name2是代理类中新增的用来调用被代理类原始方法的方法的名字
 */
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
    MethodProxy proxy = new MethodProxy();
    // Signature是用来标识一个唯一的方法
    // 该标识可以用来获取fastClass中每一个方法的索引
    proxy.sig1 = new Signature(name1, desc);
    proxy.sig2 = new Signature(name2, desc);
    proxy.createInfo = new CreateInfo(c1, c2);
    return proxy;
}

private void init()
{
    /* 
     * Using a volatile invariant allows us to initialize the FastClass and
     * method index pairs atomically.
     * 
     * Double-checked locking is safe with volatile in Java 5.  Before 1.5 this 
     * code could allow fastClassInfo to be instantiated more than once, which
     * appears to be benign.
     */
    if (fastClassInfo == null)
    {
        synchronized (initLock)
        {
            if (fastClassInfo == null)
            {
                CreateInfo ci = createInfo;
                FastClassInfo fci = new FastClassInfo();
                // helper中生成了对应Class的FastClass实例,这里可以看出就是生成了两个Class的FastClass
                fci.f1 = helper(ci, ci.c1);
                fci.f2 = helper(ci, ci.c2);
                // 获取方法的下标,sig1原本的方法名,sig2是为了调用父类方法生成的特殊方法的方法名
                fci.i1 = fci.f1.getIndex(sig1);
                fci.i2 = fci.f2.getIndex(sig2);
                // 存储在本地变量上
                fastClassInfo = fci;
                createInfo = null;
            }
        }
    }
}

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
    try {
    	// 调用init方法,当前MethodProxy所代表的方法在在FastClass中的索引
        init();
        FastClassInfo fci = fastClassInfo;
        // 这里的f2就是一个FastClass,fci.i2就是在init方法中计算出来的索引
        return fci.f2.invoke(fci.i2, obj, args);
    } catch (InvocationTargetException e) {
        throw e.getTargetException();
    }
}

public Object invoke(Object obj, Object[] args) throws Throwable {
    try {
        init();
        FastClassInfo fci = fastClassInfo;
        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;
    }
}

private static class FastClassInfo
{
	// 被代理类的FastClass
    FastClass f1;
    // 代理类的FastClass
    FastClass f2;
    int i1;
    int i2;
}
复制代码

1、可以看出在构造器中就对被代理类的目标方法和代理类的目标方法(相关的class对象以及方法名)进行了缓存

2、当调用invokeSuper()方法时就根据被代理类的方法索引(这里方法时确定的,因为每个方法一个ProxyMethod),然后利用FastClass中的invoke()方法来调用被代理类的方法

3、同理当调用invoke()方法时就调用代理类的对应方法

从而说明一个ProxyMethod对象中保存着被代理类和代理类指定方法的映射关系,并利用该关系实现FastClass的特点


FastClass机制

JDK动态代理的拦截对象是通过反射的机制来调用被拦截实例,反射的效率相对较低,故Cglib采用了FastClass的机制来实现对被拦截方法的调用

FastClass机制就是对一个类的方法建立索引,通过索引来直接调用相应的方法,下面举例进行说明:

public class User1 {
    public void select() {
        System.out.println("select user1");
    }
    public void update() {
        System.out.println("update user1");
    }
}

public class User2 {

    public Object invoke(int index,Object o,Object[] o1) {
        User1 user1 = (User1) o;
        switch (index) {
            case 1:
                user1.select();
                return null;
            case 2:
                user1.update();
                return null;
        }
        return null;
    }

    public int getIndex(String signature) {
        switch (signature.hashCode()) {
            case 3078479:
                return 1;
            case 3108270:
                return 2;
        }
        return -1;
    }
}


public class Test1 {
    public static void main(String[] args) {
        User1 user1 = new User1();
        User2 user2 = new User2();
        int index = user2.getIndex("update()V");
        user2.invoke(index,user1,null);
    }
}
复制代码

上面的例子中User2类就是User1类的FastClass,在User2类中存在两个方法getIndex()invoke(),在getIndex()方法中为User1类中的每个方法建立索引,并根据入参(方法名+方法的描述符)来返回相应的索引

getIndex()方法已经根据方法描述符返回了指定的索引,将索引传入到invoke()方法中,再将具体的对象o以及参数ol传入到方法中,最后直接通过对象调用方法(这里并不是反射)

总结:

getIndex()实际上就是建立了方法描述符的索引表,通过描述符可以获取索引

而在invoke()可以根据不同的索引调用不同的方法,从而避免了反射调用,提高效率


我们再来看下生成的两个FastClass字节码文件:

image-20210323160445162

其中的invoke()方法基本和我们前面分析的一致:

image-20210323160503865

1.4.3 Enhancer源码分析

我们上面已经知道在Cglib中有一个核心类就是Enhancer,可以用来创建代理类对象

因此我们先对该类的基本框架做一个概述:

image-20210323161308156

这里可以看出ClassGenerator是Enhancer的核心接口,其中的核心方法generateClass()用于产生目标类

image-20210323161546358

然后贴上一张Enhancer抽象调用链:

image-20210323170655519


我们下面就以之前的案例为模板debug进行分析

首先进入CglibTest类进行测试:

public class CglibTest {
    public static void main(String[] args) {
        // 在指定目录下生成动态代理类
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E:\\mygit\\java-comprehensive\\design-patterns");
        // 创建enhance对象,类似有JDK动态代理的proxy
        Enhancer enhancer = new Enhancer();
        // 设置目标类的字节码文件
        enhancer.setSuperclass(UserDao.class);
        // 设置回调函数
        enhancer.setCallback(new CustomerLogInterceptor());
        // 创建代理类对象
        UserDao user = (UserDao) enhancer.create();
        // 方法调用
        user.select();
    }
}
复制代码

这里创建了一个Enhancer对象,并向其中设置了父类以及拦截器,在执行create()方法之前来看下enhancer结构:

image-20210323162816003

这里目前存储了父类的class对象、拦截器数组、代理生成策略等...


下面就进入了关键的Enhancer#create方法

/**
 * Generate a new class if necessary and uses the specified
 * callbacks (if any) to create a new object instance.
 * Uses the no-arg constructor of the superclass.
 * @return a new instance
 */
public Object create() {
   classOnly = false;
   argumentTypes = null;
   return createHelper();
}
复制代码

从注释中可以看出这里创建一个新的class对象(如果需要),如果存在拦截器就在调用拦截器的前提下创建一个代理对象

这里首先对两个属性赋值,然后调用了createHelper()方法


Enhancer#createHelper

private Object createHelper() {
    // 对预声明的回调方法进行验证,要求 [多个回调就必须存在 CallbackFilter 作为调度器]
    preValidate();
    // 构建一个对这类增强操作唯一定位的 key
    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;
    // 调用父类通过的 create(...) 方法
    Object result = super.create(key);
    return result;
}
复制代码

1、调用preValidate()方法进行预检查,主要是对当前的拦截器进行判断

image-20210324094159450

实际上这里的filter就是一个CallbackFilter接口实例

image-20210324094320308

2、通过当前Enhancer对象内部的属性例如superClass、filter、callBackType等参数生成一个唯一的key

image-20210324094725454

3、紧接着调用父类的create()方法并传入唯一key生成了代理对象并返回,可见父类的create()方法才是实际生成代理对象


AbstractClassGenerator#create

protected Object create(Object key) {
    try {
        // 获取用于 加载 生成类 的 ClassLoader
        ClassLoader loader = getClassLoader();
        // 从缓存中加载 这个 ClassLoader 过去加载的相关数据
        Map<ClassLoader, ClassLoaderData> cache = CACHE;
        ClassLoaderData data = cache.get(loader);
        // 如果在 缓存 中找不到,则初始化构造关于这个 ClassLoader 的数据实例
        if (data == null) {
            // 同步
            synchronized (AbstractClassGenerator.class) {
                // 进入同步块后的 再次确认,避免重复初始化构建
                cache = CACHE;
                data = cache.get(loader);
                if (data == null) {
                    // 构建新的 缓存,拷贝原有的缓存集的内容
                    Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                    // 初始化 ClassLoaderData ,真正的构造操作
                    data = new ClassLoaderData(loader);
                    // 添加到缓存中
                    newCache.put(loader, data);
                    CACHE = newCache;
                }
            }
        }
        this.key = key;
        Object obj = data.get(this, getUseCache());
        if (obj instanceof Class) {
            // 初次实例化操作,就是 Class 利用反射来进行实例化
            return firstInstance((Class) obj);
        }
        // 非初次实例化,则是从 ClassLoaderData 中得到的之前维护的内容
        return nextInstance(obj);
    } catch (RuntimeException e) {
        throw e;
    } catch (Error e) {
        throw e;
    } catch (Exception e) {
        throw new CodeGenerationException(e);
    }
}
复制代码

1、首先获取类加载器,然后创建一个WeakHashMap对象cache,key为类加载器,value为ClassLoaderData对象,而这里就是直接引用了类中的CACHE静态变量

image-20210324100015391

ClassLoaderData类中包含着生成的class名称属性、已经生成的类属性、以及类加载器的弱引用等

protected static class ClassLoaderData {

private final Set<String> reservedClassNames = new HashSet<String>();

/**
    * {@link AbstractClassGenerator} here holds "cache key" (e.g. {@link org.springframework.cglib.proxy.Enhancer}
    * configuration), and the value is the generated class plus some additional values
    * (see {@link #unwrapCachedValue(Object)}.
    * <p>The generated classes can be reused as long as their classloader is reachable.</p>
    * <p>Note: the only way to access a class is to find it through generatedClasses cache, thus
    * the key should not expire as long as the class itself is alive (its classloader is alive).</p>
    */
   private final LoadingCache<AbstractClassGenerator, Object, Object> generatedClasses;

   /**
    * Note: ClassLoaderData object is stored as a value of {@code WeakHashMap<ClassLoader, ...>} thus
    * this classLoader reference should be weak otherwise it would make classLoader strongly reachable
    * and alive forever.
    * Reference queue is not required since the cleanup is handled by {@link WeakHashMap}.
    */
   private final WeakReference<ClassLoader> classLoader;

   private final Predicate uniqueNamePredicate = new Predicate() {
      public boolean evaluate(Object name) {
         return reservedClassNames.contains(name);
      }
   };
复制代码

2、然后从WeakHashMap对象cache中获取当前类加载器的ClassLoaderData对象,该类型对象我们在上面已经大致了解

3、判断当前的加载器数据对象是否存在,如果不存在就通过当前的类加载器创建一个加载器数据对象并缓存

4、对类中的key属性赋值,也就是我们传进来的参数(之前生成的唯一key)

image-20210324100809447

5、接着调用data.get(this, getUseCache())生成了代理类对象,这一步将会在1.4.3.1中进行分析

6、在下面我们会分析当前的obj可能是代理类对象,也可能是缓存中的对象,如果是缓存中的数据实际上返回的是EnhancerFactoryData对象

7、接着就判断生成的对象是否为Class类型,如果不是就调用nextInstance(obj)方法,如果是就调用firstInstance((Class) obj)方法

1.4.3.1 AbstractClassGenerator#get
public Object get(AbstractClassGenerator gen, boolean useCache) {
    // 标记为不使用缓存,直接构建 新的生成类
    if (!useCache) {
      return gen.generate(ClassLoaderData.this);
    }
    // 使用缓冲的情况
    else {
      Object cachedValue = generatedClasses.get(gen);
      return gen.unwrapCachedValue(cachedValue);
    }
}
复制代码

1、判断当前是否使用缓存,如果不使用,则调用gen.generate(ClassLoaderData.this)生成代理类对象,这里的gen从上文中看来就是当前类的this对象,其实也就是一开始的Enhancer对象

image-20210324101949509

实际上generate()也是触发ClassLoader来动态加载生成的新class对象的唯一入口,该方法将会在1.4.3.2进行分析

2、如果使用缓存,则调用generatedClasses.get(gen)尝试获取缓存值

image-20210324102720809

3、接着调用gen.unwrapCachedValue(cachedValue)并将结果作为返回值

image-20210324102512099

判断key是否为EnhancerKey,如果是则从传入的弱引用对象cache内部获取EnhancerFactoryData数据

image-20210324102842080

1.4.3.2 AbstractClassGenerator#generate
protected Class generate(ClassLoaderData data) {
    Class gen;
    Object save = CURRENT.get();
    CURRENT.set(this);
    try {
        // 拿到用于加载生成类的 ClassLoader
        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 {
                // 尝试直接通过 ClassLoader 进行加载
                gen = classLoader.loadClass(getClassName());
                return gen;
            } catch (ClassNotFoundException e) {
                // ignore
            }
        }
        // 策略下的生成类构建方法
        byte[] b = strategy.generate(this);
        // 通过解析字节码的形式获取 生成类的 className
        String className = ClassNameReader.getClassName(new ClassReader(b));
        ProtectionDomain protectionDomain = getProtectionDomain();
        synchronized (classLoader) { // just in case
            // 反射的形式加载 Class 类
            if (protectionDomain == null) {
                gen = ReflectUtils.defineClass(className, b, classLoader);
            } else {
                gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
            }
        }
        return gen;
    } catch (RuntimeException e) {
        throw e;
    } catch (Error e) {
        throw e;
    } catch (Exception e) {
        throw new CodeGenerationException(e);
    } finally {
        CURRENT.set(save);
    }
}
复制代码

1、首先获取当前类的类加载器,然后通过generateClassName()生成类名

2、然后直接通过classLoader.loadClass(getClassName())尝试让类加载器加载该类

3、strategy.generate(this) 将通过特定策略实现的形式生成新的字节码,这一部分会在1.4.3.3进行分析

4、ReflectUtils.defineClass(className,b,classLoader) 将使用反射使得 ClassLoader 来加载这个新的生成类,这里的b就是字节码文件

1.4.3.3 DefaultGeneratorStrategy#generate

我们知道这里传入的参数实际上就是Enhancer对象,因为Enhancer继承AbstractClassGenerator,从而实现了ClassGenerator

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

这里紧接着调用了ClassGenerator接口实现类的generateClass(cw)方法


Enhancer#generateClass

就是在这里生成了字节码文件并保存到ClassVisitor

public void generateClass(ClassVisitor v) throws Exception {
    // 确定生成类的 父类
    Class sc = (superclass == null) ? Object.class : superclass;

    // 父类标识符不可以为 final
    if (TypeUtils.isFinal(sc.getModifiers()))
        throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());
    // 获取父类直接声明的构造方法
    List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
    filterConstructors(sc, constructors);

    // Order is very important: must add superclass, then
    // its superclass chain, then each interface and
    // its superinterfaces.
    List actualMethods = new ArrayList();
    List interfaceMethods = new ArrayList();
    final Set forcePublic = new HashSet();
    // 从父类中提取各种信息
    getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic);

    List methods = CollectionUtils.transform(actualMethods, new Transformer() {
        public Object transform(Object value) {
            Method method = (Method)value;
            int modifiers = Constants.ACC_FINAL
                | (method.getModifiers()
                   & ~Constants.ACC_ABSTRACT
                   & ~Constants.ACC_NATIVE
                   & ~Constants.ACC_SYNCHRONIZED);
            if (forcePublic.contains(MethodWrapper.create(method))) {
                modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC;
            }
            return ReflectUtils.getMethodInfo(method, modifiers);
        }
    });

    ClassEmitter e = new ClassEmitter(v);
    if (currentData == null) {
    e.begin_class(Constants.V1_2,
                  Constants.ACC_PUBLIC,
                  getClassName(),
                  Type.getType(sc),
                  (useFactory ?
                   TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) :
                   TypeUtils.getTypes(interfaces)),
                  Constants.SOURCE_FILE);
    } else {
        e.begin_class(Constants.V1_2,
                Constants.ACC_PUBLIC,
                getClassName(),
                null,
                new Type[]{FACTORY},
                Constants.SOURCE_FILE);
    }
    List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());

    e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);
    e.declare_field(Constants.ACC_PUBLIC | Constants.ACC_STATIC, FACTORY_DATA_FIELD, OBJECT_TYPE, null);
    if (!interceptDuringConstruction) {
        e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null);
    }
    e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);
    e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null);
    if (serialVersionUID != null) {
        e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID);
    }

    for (int i = 0; i < callbackTypes.length; i++) {
        e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null);
    }
    // This is declared private to avoid "public field" pollution
    e.declare_field(Constants.ACC_PRIVATE | Constants.ACC_STATIC, CALLBACK_FILTER_FIELD, OBJECT_TYPE, null);

    if (currentData == null) {
        emitMethods(e, methods, actualMethods);
        emitConstructors(e, constructorInfo);
    } else {
        emitDefaultConstructor(e);
    }
    emitSetThreadCallbacks(e);
    emitSetStaticCallbacks(e);
    emitBindCallbacks(e);

    if (useFactory || currentData != null) {
        int[] keys = getCallbackKeys();
        emitNewInstanceCallbacks(e);
        emitNewInstanceCallback(e);
        emitNewInstanceMultiarg(e, constructorInfo);
        emitGetCallback(e, keys);
        emitSetCallback(e, keys);
        emitGetCallbacks(e);
        emitSetCallbacks(e);
    }

    e.end_class();
}
复制代码

个人公众号目前正初步建设中,如果喜欢可以关注我的公众号,谢谢!

文章分类
后端
文章标签