CGLIB入门系列三,CGLIB生成的代理类详解

此前一直有一个疑惑,那就是为什么CGLIB生成代理类的时候会出现三个class文件,按道理说应该只有一个,多出来的两个类怎么回事?
其实多出来的这两个class类就是为CGLIB中重要的fastClass机制而生成的。

实验

public class GoodsService {

    @Test
    public void placeOrder() {
        System.out.println("place order");
        MsgUtil.addMsg("place order");
    }

    public void place() {
        throw new RuntimeException();
    }

    @Override
    public String toString() {
        return "GoodsService{}";
    }
}

@Test
public void testEnhance() {
	// 获取CGLIB生成的字节码
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\Users\\12130\\Desktop\\新建文件夹");
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(GoodsService.class);
    enhancer.setCallback(new TransactionInterceptor());
    GoodsService goodsService = (GoodsService) enhancer.create();
    goodsService.placeOrder();
}

static class TransactionInterceptor implements MethodInterceptor {
	/**
	 * 参数1:代理类对象实例
	 * 参数2:被代理的原始方法
	 * 参数3:方法参数
	 * 参数4:fastClass机制相关
	 */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("start interceptor");
        // 为什么要执行的是invokeSuper,而不是直接invoke?
        Object obj = methodProxy.invokeSuper(o, objects);
        System.out.println("end interceptor");
        return obj;
    }
}

FastClass机制

Jdk动态代理的拦截对象是通过反射的机制来调用被拦截实例方法的,反射的效率比较低,所以cglib采用了FastClass的机制来实现对被拦截方法的调用。FastClass机制就是对一个类的方法建立索引,调用方法时根据方法的签名来计算索引,通过索引来直接调用相应的方法。
这也就是为什么CGLIB生成的动态代理会包含3个class文件的原因,其中一个是生成的代理类,另外两个类都是FastClass机制需要的。另外两个类都继承了FastClass这个类。其中一个class为生成的代理类中的每个方法建立了索引,另外一个则为我们被代理类的所有方法包含其父类的方法建立了索引。
下面这个就是为被代理类中的方法建立的索引。

public class GoodsService$$FastClassByCGLIB$$58067f53 extends FastClass {
    public GoodsService$$FastClassByCGLIB$$58067f53(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case 1203662734:
            if (var10000.equals("placeOrder()V")) {
                return 1;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 3;
            }
            break;
        case 1858883854:
            if (var10000.equals("place()V")) {
                return 2;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 0;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 4;
            }
        }

        return -1;
    }
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        GoodsService var10000 = (GoodsService)var2;
        int var10001 = var1;

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

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

可以看出,利用上面的invoke方法,只要我们传入对应方法的下标和实例对象,就可以非常快的调用到对应的方法。

FastClass类是在哪生成的?是如何生效的?

我们先看看CGLIB为我们生成的代理类

代理类分析

在示例代码中我们通过设置DebuggingClassWriter.DEBUG_LOCATION_PROPERTY的属性值来获取cglib生成的代理类
下面是生成代理类的字节码

public class GoodsService$$EnhancerByCGLIB$$b08e58d5 extends GoodsService 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$toString$0$Method;
    // MethodProxy与FastClass机制有关,下面会讲
    private static final MethodProxy CGLIB$toString$0$Proxy;
    // 空参数,一个默认值,当我们的方法没有参数的时候会传递给拦截器
    // 不传递空值,这是一种设置思想
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$placeOrder$1$Method;
    private static final MethodProxy CGLIB$placeOrder$1$Proxy;
    private static final Method CGLIB$place$2$Method;
    private static final MethodProxy CGLIB$place$2$Proxy;
    private static final Method CGLIB$equals$3$Method;
    private static final MethodProxy CGLIB$equals$3$Proxy;
    private static final Method CGLIB$hashCode$4$Method;
    private static final MethodProxy CGLIB$hashCode$4$Proxy;
    private static final Method CGLIB$clone$5$Method;
    private static final MethodProxy CGLIB$clone$5$Proxy;
	
	// 该方法会在静态代码块中被调用,对上面的变量进行初始化
    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.cp.v5.service.GoodsService$$EnhancerByCGLIB$$b08e58d5");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$3$Method = var10000[0];
        // 创建MethodProxy,每一个方法都会创建一个对应的MethodProxy
        // 当前代理会会为其所有父类的方法都创建对应的MethodProxy,
        CGLIB$equals$3$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
        CGLIB$hashCode$4$Method = var10000[1];
        CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
        CGLIB$clone$5$Method = var10000[2];
        CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
        // 获取GoodsService这个父类的所有方法
        var10000 = ReflectUtils.findMethods(new String[]{"toString", "()Ljava/lang/String;", "placeOrder", "()V", "place", "()V"}, (var1 = Class.forName("com.cp.v5.service.GoodsService")).getDeclaredMethods());
        CGLIB$toString$0$Method = var10000[0];
        CGLIB$toString$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$0");
        CGLIB$placeOrder$1$Method = var10000[1];
        CGLIB$placeOrder$1$Proxy = MethodProxy.create(var1, var0, "()V", "placeOrder", "CGLIB$placeOrder$1");
        CGLIB$place$2$Method = var10000[2];
        CGLIB$place$2$Proxy = MethodProxy.create(var1, var0, "()V", "place", "CGLIB$place$2");
    }
	
	/**
	 * 用来调用父类的原始方法
	 * CGLIB生成代理利用的是继承,而不是JDK动态代理的利用接口的形式
	 * 这样就有一个区别就出现了,JDK动态代理中必须要有一个被代理类的实例
	 * 但是CGLIB实现的动态代理就不需要,因为是继承,所以就包含了被代理类的全部方法
	 * 但是我们调用生成的代理类实例的toString()方法时,调用的就是CGLIB代理时候的方法
	 * 如果调用被代理类的原始方法呢,就是靠下面的这个方法
	 * CGLIB生成的代理类中每个原始方法都会有这两种类型的方法
	 */
    final String CGLIB$toString$0() {
        return super.toString();
    }
	
	/**
	 * 生成的代理方法,在该方法中会调用我们设置的Callback
	 * 当调用代理类的toString方法时,先判断是否已经存在实现了MethodInterceptor接口的拦截对象
	 * 如果没有的话就调用CGLIB$BIND_CALLBACKS方法来获取Callback
	 */
    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
		
        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$0$Method, CGLIB$emptyArgs, CGLIB$toString$0$Proxy) : super.toString();
    }
	
	/**
	 * 删除了类似toString这样生成的方法,也都是一一对应的
	 * 还有几个newInstance()方法,newInstance()方法来源于Factory接口
	 * 从上面可以看到生成的代理类实现了Factory接口
	 */

    public GoodsService$$EnhancerByCGLIB$$b08e58d5() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }
	
	/**
	 * 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) {
        GoodsService$$EnhancerByCGLIB$$b08e58d5 var1 = (GoodsService$$EnhancerByCGLIB$$b08e58d5)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }
            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        default:
            var10000 = null;
        }

        return var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        default:
        }
    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}

在生成的代理类字节码中,有一个静态代码块,他执行了重要的方法

static {
    CGLIB$STATICHOOK1();
}

static void CGLIB$STATICHOOK1() {
    CGLIB$THREAD_CALLBACKS = new ThreadLocal();
    CGLIB$emptyArgs = new Object[0];
    /**
     * 为被代理类所有方法生成一个MethodProxy对象,包含其所有父类的方法
     */
    Class var0 = Class.forName("com.cp.v5.service.GoodsService$$EnhancerByCGLIB$$b08e58d5");
    Class var1;
    // 获取Object这个父类的所有方法,会将其所有的方法保存到一个本地变量上,并且会生成一个MethodProxy
    // 这个MethodProxy的对象实例很重要,MethodInterceptor的intercept方法就需要该对象实例,用来进行快速调用
    Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
    CGLIB$equals$3$Method = var10000[0];
    CGLIB$equals$3$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
    CGLIB$hashCode$4$Method = var10000[1];
    CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
    CGLIB$clone$5$Method = var10000[2];
    CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
    // 获取GoodsService这个父类的所有方法
    var10000 = ReflectUtils.findMethods(new String[]{"toString", "()Ljava/lang/String;", "placeOrder", "()V", "place", "()V"}, (var1 = Class.forName("com.cp.v5.service.GoodsService")).getDeclaredMethods());
    CGLIB$toString$0$Method = var10000[0];
    CGLIB$toString$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$0");
    CGLIB$placeOrder$1$Method = var10000[1];
    CGLIB$placeOrder$1$Proxy = MethodProxy.create(var1, var0, "()V", "placeOrder", "CGLIB$placeOrder$1");
    CGLIB$place$2$Method = var10000[2];
    CGLIB$place$2$Proxy = MethodProxy.create(var1, var0, "()V", "place", "CGLIB$place$2");
}	

CGLIB$STATICHOOK1()这个静态方法内执行了MethodProxy.create()方法,为被代理所有的方法都生成了对应的MethodProxy,在调用代理对象的每个方法是都会有一个对应的MethodProxy就会当参数被传递到MethodInterceptor.intercept()方法中,在intercept中就能利用MethodProxy类的方法,使用FastClass机制

MethodProxy中的部分方法

/**
 * 一个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;
}

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
1 Spring基本特征 6 2 Spring的组成 6 2.1 Spring的jar包 6 2.2 Spring配置文件 7 2.3 Spring API 8 3 Spring基本功能详解 8 3.1 SpringIOC 8 3.2别名Alias 11 别名拓展: 11 3.3 Spring容器内部对象的创建 12 Spring容器内部对象创建拓展: 12 3.3.1使用构造器实例化(默认无参数) 14 3.3.2使用静态工厂方法实例化(简单工厂模式) 14 3.3.3初始化(创建)bean时机 15 Lazy-init初始化bean的时机拓展: 15 3.4 Bean的作用域 16 Scope单例多例作用域拓展: 16 3.4.1 singleton(默认值) 16 3.4.2 prototype 17 3.4.3 Request 17 3.4.4 Session 18 3.4.5 Global session 18 3.4.6 指定Bean的初始化方法和销毁方法 18 Bean的初始化和销毁拓展: 18 Spring的IOC总结: 20 3.5 依赖注入(DI) 20 3.5.1 使用构造器注入 20 3.5.2 使用属性setting方法进行注入 21 3.5.3 装配list集合 22 3.5.4 装配set集合 22 3.5.5 装配map 22 3.5.6 装配Properties 23 3.6 注解注入 23 注解注入拓展: 23 3.6.1 @Autowired 26 3.6.2 @Qualifier 27 3.6.3 @Resource 27 3.6.4 @PostConstruct 28 3.6.5 @PreDestroy 28 注解注入拓展: 28 3.7扫描注入 30 注解扫描拓展: 32 Mvc用注解写: 34 Spring容器IOC和di的整个启动过程: 38 3.8 spring中的继承 38 拓展spring为中的属性赋值: 40 小结: 47 面向接口编程: 47 4 面向切面编程 52 4.1 代理模式 52 代理模式拓展: 52 4.1.1 JDK动态代理 58 JDK动态代理拓展: 59 4.1.2 CGLIB代理 66 CGLIB动态代理拓展: 68 4.1.3 Spring的动态代理 71 4.2 AOP编程 71 4.2.1概念: 71 SpringAOP概念拓展: 73 之前实现了目标方法的动态调用,现在来实现切面的动态调用。 74 4.2.2 AOP实现的两种模式 78 4.2.2.1 xml形式 78 XML形式拓展: 81 异常通知处理例子: 91 不用spring异常通知,另一种处理异常 96 4.2.2.2Aop注解形式(了解) 99 注解注入拓展: 103 5 Spring数据库 106 5.1 Spring+JDBC 106 5.1.1 Jdbc编程特点 106 5.1.2引入DataSource 106 5.1.3 核心JdbcTemplate 106 5.1.4 使用JdbcTemplate 106 5.1.5 继承JdbcDaoSupport 107 5.1.6 使用properties文件 107 5.1.7 RowMapper的使用 107 拓展: 108 DataSource注入的种方式: 108 5.1.8声明式事务管理 116 5.1.8.1Spring的事务管理器 117 5.1.8.2Spring事务的传播属性 117 5.1.8.3Spring事务的隔离级别 117 拓展: 118 5.1.8.4以XML配置的 形式 119 拓展: 120 5.1.8.5以注解方式配置 125 拓展: 127 5.1.9使用CGLIB以XML形式配置事务 130 5.2 Spring+Hibernate 131 5.2.1 HibernateTemplate模板 131 5.2.2 声明式事务 131 配置XML文件 131 拓展: 132 注解形式: 137 拓展: 138 6 Struts2+spring+hibernate 141 6.1 需要添加的jar包 141 6.2 Spring融合web服务器 141 6.3 struts.xml文件 143 6.4 OpenInSessionView 143 拓展: 144 实例: 146
《Java 基础核心总结》 Java 概述 什么是 Java2 Java 的特点Java 开发环境 JDK JRE Java 开发环境配置 Java 基本语法 数据型基础语法运算符 Java 执行控制流程条件语句 if 条件语句 if...else 条件语句if...else if 多分支语句switch 多分支语句 循环语句 while 循环语句do...while 循环for 循环语句 跳转语句 break 语句 continue 语句面向对象 也是-种对象对象的创建 属性和方法 构造方法 方法重载 方法的重写 初始化 的初始化 成员初始化 构造器初始化初始化顺序 数组初始化 对象的销毁 对象作用域 this 和 super 访问控制权限继承 多态组合代理 向上转型static final 接口和抽象接口 抽象异常 认 识 Exception 什么是 Throwable 常见的 Exception 与 Exception 有关的 Java 关键字 throws 和 throw try 、finally 、catch 什么是 Error 内部 创建内部集合 Iterable 接口顶层接口 ArrayList Vector LinkedList Stack HashSet TreeSet LinkedHashSet PriorityQueue HashMap TreeMap LinkedHashMap Hashtable IdentityHashMap WeakHashMap Collections 集合实现特征图 泛形 泛型的使用 用泛型表示 用泛型表示接口泛型方法 泛型通配符 反射 Class Field Method ClassLoader 枚举 枚举特性 枚举和普通-样枚举神秘之处 枚举 I/O File 基础 IO 和相关方法InputStream OutputStream Reader Writer InputStream 及其子 OutputStream 及其子Reader 及其子Writer 及其子 注解 关于 null 的几种处理方式大小写敏感 null 是任何引用型的初始值 null 只是-种特殊的值使用 Null-Safe 方法null 判断 关于思维导图 Java.IO Java.lang Java.math Java.net Java 基础核心总结 V2.0 IO 传统的 BIO BIO NIO 和 AIO 的区别什么是流 流的分 节点流和处理流 Java IO 的核心 File Java IO 流对象 字节流对象InputStream OutputStream 字符流对象Reader Writer 字节流与字符流的转换新潮的 NIO 缓冲区(Buffer)通道(Channel) 示例:文件拷贝案例 BIO 和 NIO 拷贝文件的区别操作系统的零拷贝 选择器(Selectors) 选择键(SelectionKey) 示例:简易的客户端服务器通信 集合 集合框架总览 -、Iterator Iterable ListIterator 二、Map 和 Collection 接口Map 集合体系详解 HashMap LinkedHashMap TreeMap WeakHashMap Hashtable Collection 集合体系详解 Set 接口 AbstractSet 抽象SortedSet 接口HashSet LinkedHashSet TreeSet List 接口 AbstractList 和 AbstractSequentialList Vector Stack ArrayList LinkedList Queue接口Deque 接口 AbstractQueue 抽象LinkedList ArrayDeque PriorityQueue 反射的思想及作用 反射的基本使用 获取Class 对象构造的实例化对象获取-个的所有信息 获取中的变量(Field) 获取中的方法(Method) 获取的构造器(Constructor) 获取注解 通过反射调用方法反射的应用场景 Spring 的 IOC 容器反射 + 抽象工厂模式 JDBC 加载数据库驱动反射的优势及缺陷 增加程序的灵活性破坏的封装性 性能损耗 代理模式 静态代理动态代理常见的动态代理实现JDK Proxy CGLIB JDK Proxy 和 CGLIB 的对比动态代理的实际应用 Spring AOP 变量 变量汇总实例变量 实例变量的特点全局变量 静态变量 静态变量的特点变量 局部变量
CGLIB动态代理和JDK动态代理都是常见的Java动态代理技术,它们在实现原理和使用方式上有一些区别。CGLIB动态代理是通过继承目标生成代理,而JDK动态代理是通过实现目标的接口来生成代理CGLIB动态代理相比JDK动态代理有以下几个优势: 1. 性能更高:CGLIB动态代理生成代理时,不需要像JDK动态代理那样通过反射调用目标方法,而是直接调用目标的方法,因此在性能上更高效。 2. 支持非接口CGLIB动态代理可以代理没有实现接口的,而JDK动态代理只能代理实现了接口的。 3. 不受final修饰符限制:CGLIB动态代理可以代理被final修饰的和方法,而JDK动态代理无法代理final修饰的和方法。 然而,CGLIB动态代理也有一些限制和缺点: 1. CGLIB动态代理生成代理是目标的子,因此无法代理被final修饰的和方法。 2. CGLIB动态代理使用字节码生成技术,对于一些复杂的场景可能会导致生成代理过于庞大,影响性能和加载速度。 3. CGLIB动态代理需要依赖CGLIB库,而JDK动态代理是Java标准库的一部分,因此在一些特定的环境中可能无法使用CGLIB动态代理。 综上所述,CGLIB动态代理在性能和功能上相对于JDK动态代理有一些优势,但也存在一些限制和缺点。选择使用哪种动态代理技术应根据具体的需求和场景来决定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值