8.CGLIB动态代理源码之FastClass

445 阅读6分钟

使用示例

package fastclass;
​
public class DelegateClass {
​
    public DelegateClass() {
    }
​
    public DelegateClass(String string) {
    }
​
    public boolean eat(String fruit, int i) {
        System.out.println(" eat " + i + "个" + fruit);
        return true;
    }
​
    public void drink() {
        System.out.println("drink water");
    }
}
package fastclass;
​
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.reflect.FastClass;
​
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
​
/**
 * @author: claude-彭方亮
 * @package: fastclass.ReflectAndFastClass
 * @date: 2023/3/8 11:40
 * @description: TODO
 * @version: 1.0
 */
public class ReflectAndFastClass {
​
    public static void invokeReflect() throws Exception {
        Class delegateClass = DelegateClass.class;
        // 反射构造类
        Constructor delegateConstructor = delegateClass.getConstructor(String.class);
        // 创建委托类实例
        DelegateClass delegateInstance = (DelegateClass) delegateConstructor.newInstance("tyrant");
        // 反射方法类
        Method addMethod = delegateClass.getMethod("eat", String.class, int.class);
        // 调用方法
        addMethod.invoke(delegateInstance, "apple", 1);
        Method updateMethod = delegateClass.getMethod("drink");
        updateMethod.invoke(delegateInstance);
    }
​
​
    public static void invokeFastClass() throws Exception {
        // 保留生成的FastClass类文件
        //System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "e:\proxy");
        // FastClass动态子类实例
        FastClass fastClass = FastClass.create(DelegateClass.class);
        // 创建委托类实例
        DelegateClass fastInstance = (DelegateClass) fastClass.newInstance(
                new Class[] {String.class}, new Object[]{"Jack"});
        // 调用委托类方法
        fastClass.invoke("eat", new Class[]{ String.class, int.class}, fastInstance,
                new Object[]{ "fruit", 2});
        fastClass.invoke("drink", new Class[]{}, fastInstance, new Object[]{});
    }
​
​
    public static void main(String[] args) throws Exception {
 
            invokeReflect();
 
            invokeFastClass();
 
    }
}

原理分析

FastClass不使用反射类(Constructor或Method)来调用委托类方法,而是动态生成一个新的类(继承FastClass),向类中写入委托类实例直接调用方法的语句,用模板方式解决Java语法不支持问题,同时改善Java反射性能。 动态类为委托类方法调用语句建立索引,使用者根据方法签名(方法名+参数类型)得到索引值,再通过索引值进入相应的方法调用语句,得到调用结果。

  public abstract class FastClass{
 
     // 委托类
     private Class type;
     
     // 子类访问构造方法
     protected FastClass() {}
     protected FastClass(Class type) {
         this.type = type;
     }
     
     // 创建动态FastClass子类
     public static FastClass create(Class type) {
         // Generator:子类生成器,继承AbstractClassGenerator
         Generator gen = new Generator();
         gen.setType(type);
         gen.setClassLoader(type.getClassLoader());
         return gen.create();
     }
     
     /**
      * 调用委托类方法
      *
      * @param name 方法名
      * @param parameterTypes 方法参数类型
      * @param obj 委托类实例
      * @param args 方法参数对象
      */
     public Object invoke(String name, Class[] parameterTypes, Object obj, Object[] args) {
         return invoke(getIndex(name, parameterTypes), obj, args);
     }
     
     /**
      * 根据方法描述符找到方法索引
      *
      * @param name 方法名
      * @param parameterTypes 方法参数类型
      */
     public abstract int getIndex(String name, Class[] parameterTypes);
     
     
     /**
      * 根据方法索引调用委托类方法
      *
      * @param index 方法索引
      * @param obj 委托类实例
      * @param args 方法参数对象
      */
     public abstract Object invoke(int index, Object obj, Object[] args);
     
     /**
      * 调用委托类构造方法
      * 
      * @param parameterTypes 构造方法参数类型
      * @param args 构造方法参数对象
      */
     public Object newInstance(Class[] parameterTypes, Object[] args) throws {
         return newInstance(getIndex(parameterTypes), args);
     }
     
     /**
      * 根据构造方法描述符(参数类型)找到构造方法索引
      *
      * @param parameterTypes 构造方法参数类型
      */
     public abstract int getIndex(Class[] parameterTypes);
     
     /**
      * 根据构造方法索引调用委托类构造方法
      *
      * @param index 构造方法索引
      * @param args 构造方法参数对象
      */
     public abstract Object newInstance(int index, Object[] args);
     
 }

FastClass分析

 public class DelegateClass$$FastClassByCGLIB$$4af5b667 extends FastClass {
    
    /**
     * 动态子类构造方法
     */
    public DelegateClass$$FastClassByCGLIB$$4af5b667(Class delegateClass) {
        super(delegateClass);
    }
​
    /**
     * 根据方法签名得到方法索引
     *
     * @param name 方法名
     * @param parameterTypes 方法参数类型
     */
    public int getIndex(String methodName, Class[] parameterTypes) {
        switch(methodName.hashCode()) {
            
            // 委托类方法add索引:0
            case 96417:
                if (methodName.equals("add")) {
                    switch(parameterTypes.length) {
                        case 2:
                            if (parameterTypes[0].getName().equals("java.lang.String") && 
                                parameterTypes[1].getName().equals("int")) {
                                return 0;
                            }
                    }
                }
                break;
            
            // 委托类方法update索引:1
            case -838846263:
                if (methodName.equals("update")) {
                    switch(parameterTypes.length) {
                        case 0:
                            return 1;
                    }
                }
                break;
                
            // Object方法equals索引:2
            case -1295482945:
                if (methodName.equals("equals")) {
                    switch(parameterTypes.length) {
                        case 1:
                            if (parameterTypes[0].getName().equals("java.lang.Object")) {
                                return 2;
                            }
                    }
                }
                break;
            
            // Object方法toString索引:3
            case -1776922004:
                if (methodName.equals("toString")) {
                    switch(parameterTypes.length) {
                        case 0: return 3;
                    }
                }
                break;
            
            // Object方法hashCode索引:4
            case 147696667:
                if (methodName.equals("hashCode")) {
                    switch(parameterTypes.length) {
                        case 0:
                            return 4;
                    }
                }
        }
​
        return -1;
    }
    
    /**
     * 根据方法索引调用委托类方法
     *
     * @param methodIndex 方法索引
     * @param delegateInstance 委托类实例
     * @param parameterValues 方法参数对象
     */
    public Object invoke(int methodIndex, Object delegateInstance, Object[] parameterValues) {
        DelegateClass instance = (DelegateClass) delegateInstance;
        int index = methodIndex;
        try {
            switch(index) {
                case 0:
                    // 委托类实例直接调用方法语句
                    return new Boolean(instance.add((String)parameterValues[0], 
                            ((Number)parameterValues[1]).intValue()));
                case 1:
                    instance.update();
                    return null;
                case 2:
                    return new Boolean(instance.equals(parameterValues[0]));
                case 3:
                    return instance.toString();
                case 4:
                    return new Integer(instance.hashCode());
            }
        } catch (Throwable t) {
            throw new InvocationTargetException(t);
        }
​
        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
​
    /**
     * 根据构造方法描述符(参数类型)找到构造方法索引
     *
     * @param parameterTypes 构造方法参数类型
     */
    public int getIndex(Class[] parameterTypes) {
        switch(parameterTypes.length) {
            // 无参构造方法索引:0
            case 0:
                return 0;
            
            // 有参构造方法索引:1
            case 1:
                if (parameterTypes[0].getName().equals("java.lang.String")) {
                    return 1;
                }
            default:
                return -1;
        }
    }
    
    /**
     * 根据构造方法索引调用委托类构造方法
     *
     * @param methodIndex 构造方法索引
     * @param parameterValues 构造方法参数对象
     */
    public Object newInstance(int methodIndex, Object[] parameterValues) {
        // 创建委托类实例
        DelegateClass newInstance = new DelegateClass;
        DelegateClass newObject = newInstance;
        int index = methodIndex;
        try {
            switch(index) {
                // 调用构造方法(<init>)
                case 0:
                    newObject.<init>();
                    return newInstance;
                case 1:
                    newObject.<init>((String)parameterValues[0]);
                    return newInstance;
            }
        } catch (Throwable t) {
            throw new InvocationTargetException(t);
        }
​
        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
​
    public int getMaxIndex() {
        return 4;
    }
}

效率比较

FastClass和反射运行效率比较

package fastclass;
​
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;
​
import java.lang.reflect.Method;
​
/**
 * 效率测试
 *
 * @author Stone.J 2010-9-15 上午10:07:27
 */
public class Productiveness {
​
    private static final int DEFAULT_INT = 1;
    private static final Integer DEFAULT_INTEGER = 1;
    private static final String DEFAULT_STRING = "name";
    private static final Object[] DEFAULT_INTS = {1};
    private static final Object[] DEFAULT_INTEGERS = new Integer[]{1};
    private static final Object[] DEFAULT_STRINGS = new String[]{"name"};
​
    private static final Bean BEAN = new Bean();
​
    private static final CachedMethod CACHED_METHOD = new CachedMethod();
    private static final OptimizationCachedMethod OPTIMIZATION_CACHED_METHOD = new OptimizationCachedMethod();
    private static final CglibCachedMethod CGLIB_CACHED_METHOD = new CglibCachedMethod();
​
    private static final long LOOP = 1 * 10000 * 10000;
​
    // 测试main
    public static void main(String[] args) {
        // 直接调用
        test();
        // 反射调用
        testReflection();
        // 优化后反射调用
        testOptimizationReflection();
        // cglib反射调用
        testCglibReflection();
    }
​
    // 直接调用测试
    public static void test() {
        long start = System.currentTimeMillis();
        for (long i = 0; i < LOOP; i++) {
            BEAN.setId(DEFAULT_INT);
            BEAN.setCode(DEFAULT_INTEGER);
            BEAN.setName(DEFAULT_STRING);
        }
        long dur = System.currentTimeMillis() - start;
        System.out.println("直接调用测试:" + dur);
    }
​
    // 反射调用测试
    public static void testReflection() {
        long start = System.currentTimeMillis();
        for (long i = 0; i < LOOP; i++) {
            try {
                CACHED_METHOD.setId.invoke(BEAN, DEFAULT_INTS);
                CACHED_METHOD.setCode.invoke(BEAN, DEFAULT_INTEGERS);
                CACHED_METHOD.setName.invoke(BEAN, DEFAULT_STRINGS);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        long dur = System.currentTimeMillis() - start;
        System.out.println("反射调用测试:" + dur);
    }
​
    // 优化后反射调用测试
    public static void testOptimizationReflection() {
        long start = System.currentTimeMillis();
        for (long i = 0; i < LOOP; i++) {
            try {
                OPTIMIZATION_CACHED_METHOD.setId.invoke(BEAN, DEFAULT_INTS);
                OPTIMIZATION_CACHED_METHOD.setCode.invoke(BEAN, DEFAULT_INTEGERS);
                OPTIMIZATION_CACHED_METHOD.setName.invoke(BEAN, DEFAULT_STRINGS);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        long dur = System.currentTimeMillis() - start;
        System.out.println("优化后反射调用测试:" + dur);
    }
​
    // cglib反射调用测试
    public static void testCglibReflection() {
        long start = System.currentTimeMillis();
        for (long i = 0; i < LOOP; i++) {
            try {
                CGLIB_CACHED_METHOD.cglibSetId.invoke(BEAN, DEFAULT_INTS);
                CGLIB_CACHED_METHOD.cglibSetCode.invoke(BEAN, DEFAULT_INTEGERS);
                CGLIB_CACHED_METHOD.cglibSetName.invoke(BEAN, DEFAULT_STRINGS);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        long dur = System.currentTimeMillis() - start;
        System.out.println("cglib反射调用测试:" + dur);
    }
​
    /**
     * <pre>
     * 测试的bean
     * 简单的int Integer String类型
     * </pre>
     *
     * @author Stone.J 2010-9-15 上午10:40:40
     */
    public static class Bean {
​
        private int id;
        private Integer code;
        private String name;
​
        public int getId() {
            return id;
        }
​
        public void setId(int id) {
            this.id = id;
        }
​
        public Integer getCode() {
            return code;
        }
​
        public void setCode(Integer code) {
            this.code = code;
        }
​
        public String getName() {
            return name;
        }
​
        public void setName(String name) {
            this.name = name;
        }
​
    }
​
    /**
     * 反射测试需要:Cached Method
     *
     * @author Stone.J 2010-9-15 上午10:41:04
     */
    public static class CachedMethod {
​
        public Method setId;
        public Method setCode;
        public Method setName;
​
        {
            try {
                setId = Bean.class.getDeclaredMethod("setId", int.class);
                setCode = Bean.class.getDeclaredMethod("setCode", Integer.class);
                setName = Bean.class.getDeclaredMethod("setName", String.class);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
​
    }
​
    /**
     * 反射测试需要:优化后的Cached Method
     *
     * @author Stone.J 2010-9-15 上午10:41:21
     */
    public static class OptimizationCachedMethod extends CachedMethod {
​
        {
            /** 所谓的优化 */
            setId.setAccessible(true);
            setCode.setAccessible(true);
            setName.setAccessible(true);
        }
​
    }
​
    /**
     * 反射测试需要,使用cglib的fast method
     *
     * @author Stone.J 2010-9-15 上午10:51:53
     */
    public static class CglibCachedMethod extends CachedMethod {
​
        public FastMethod cglibSetId;
        public FastMethod cglibSetCode;
        public FastMethod cglibSetName;
​
        private FastClass cglibBeanClass = FastClass.create(Bean.class);
​
        {
            cglibSetId = cglibBeanClass.getMethod(setId);
            cglibSetCode = cglibBeanClass.getMethod(setCode);
            cglibSetName = cglibBeanClass.getMethod(setName);
        }
​
    }
​
}

测试了2次结果差别并不大:

直接调用测试:93
反射调用测试:1352
优化后反射调用测试:1301
cglib反射调用测试:361
直接调用测试:92
反射调用测试:1359
优化后反射调用测试:1276
cglib反射调用测试:385

参考地址:www.manongjc.com/detail/7-yu…

参考地址:www.cnblogs.com/laoxia/p/11…

参考地址:www.ngui.cc/el/1652226.…

cglib通过fastclass类来避免了java反射的使用。对jdk7以前的版本来说,jdk动态代理执行效率明显要比cglib动态代理类效率差,jdk8即以后版本对jdk动态代理进行了相应的优化,这种差距就不那么明显了。

参考地址:www.bbsmax.com/A/D854jlgQz…