JDK动态代理和CGlib代理的区别

我们通常说的动态代理主要有JDK的动态代理和CGLIB代理,Spring的AOP也是基于这两种代理实现的。

下面我们先从代码上来了解一下这两种代理。

被代理类

public class Teacher implements Person {

    public void sleep(){
        System.out.println("sleeping");
    }

    public void teach(){
        System.out.println("teaching");
    }
}

JDK动态代理

JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理

我们先抽象出一个接口,让被代理类去实现。

public interface Person {

    public void sleep();

    public void teach();
}

然后代理类实现InvocationHandler接口

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKProxy2 implements InvocationHandler{

    private Object object;

    public Object getPersonProxy(Object object){
        this.object = object;
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("进入方法:" + method.getName() + " " + start);
        Object result = method.invoke(object, args);
        long end = System.currentTimeMillis();
        System.out.println("结束方法:" + method.getName() + " " + end);
        return result;
    }

}

cglib动态代理

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

需要依赖jar包,maven依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

代理类

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor {

    private Object object;

    public Object getProxy(Object object){
        this.object = object;
        //创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();
        //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        enhancer.setSuperclass(object.getClass());
        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
        enhancer.setCallback(this);
        // 创建动态代理类对象并返回 
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("进入方法:" + method.getName() + " " + start);
        Object result = method.invoke(object, args);
        long end = System.currentTimeMillis();
        System.out.println("结束方法:" + method.getName() + " " + end);
        return result;
    }

}

测试类

public class Test {
    public static void main(String[] args) {
        Person person = (Person)new JDKProxy().getPersonProxy(new Teacher());
        person.sleep();
        person.teach();
        System.out.println("------------------------");
        Person person2 = (Person)new JDKProxy2().getPersonProxy(new Teacher());
        person2.sleep();
        person2.teach();
        System.out.println("------------------------");
        Teacher teacher = (Teacher)new CglibProxy().getProxy(new Teacher());
        teacher.sleep();
        teacher.teach();

    }
}

控制台输出

进入方法:sleep 1505810963080
sleeping
结束方法:sleep 1505810963081
进入方法:teach 1505810963081
teaching
结束方法:teach 1505810963081
------------------------
进入方法:sleep 1505810963081
sleeping
结束方法:sleep 1505810963081
进入方法:teach 1505810963081
teaching
结束方法:teach 1505810963081
------------------------
进入方法:sleep 1505810963162
sleeping
结束方法:sleep 1505810963162
进入方法:teach 1505810963162
teaching
结束方法:teach 1505810963162

比较

JDK动态代理
  • 不需要依赖第三方库
  • 通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法,所以必须实现接口
  • 可以通过实现InvocationHandler,或者构造InvocationHandler匿名内部类实现
  • 通过Proxy.newProxyInstance方法创建代理接口的代理类
CGLIB
  • 必须依赖CGLIB类库
  • 通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理,所以需要代理的方法不能被final修饰
  • 代理类必须实现MethodInterceptor拦截器,重写其intercept方法
  • 通过new Enhancer()创建加强器
  • 如果类被final修饰,那么不能使用CGLIB代理,因为被final修饰的类不允许生成子类

Spring AOP的选择

  • 当Bean实现接口时,Spring就会用JDK的动态代理
  • 当Bean没有实现接口时,Spring使用CGlib是实现
  • 可以强制使用CGlib(在spring配置中加入)

喜欢这篇文章的朋友,欢迎长按下图关注公众号lebronchen,第一时间收到更新内容。
扫码关注

<think>嗯,用户想了解JDK动态代理CGLIB动态代理区别,以及它们的适用场景。首先,我需要回忆一下这两种代理的基本概念工作原理。JDK动态代理是基于接口的,而CGLIB是通过继承目标类来实现代理的。这一点应该是最主要的区别。然后,我需要考虑它们的依赖关系,JDK不需要额外库,而CGLIB需要。性能方面,可能CGLIB在生成代理时比较慢,但调用方法时更快?或者是反过来?可能需要查一下引用资料。 根据引用[3],提到JDK只能代理接口,性能较低,而CGLIB可以代理类,性能较高。但引用[4]指出Spring AOP默认根据目标对象是否有接口来选择,如果有接口用JDK,没有的话用CGLIB。所以适用场景方面,如果目标类有接口就用JDK,否则用CGLIB。另外,CGLIB不能代理final类或方法,这也是一个限制。 然后,我需要组织这些信息,按照实现原理、代理对象类型、依赖、性能、限制等方面来分点回答。还要确保使用正确的中文表达,并且按照用户的要求,行内公式用$...$,不过这里可能用不上数学公式。但用户可能有其他问题,比如生成相关问题,所以最后要准备几个相关问题,比如两者的性能对比,如何选择,在Spring中的配置等。 需要确认引用是否正确。引用[1]提到了两者的代理工厂实现接口的不同,引用[2][3]补充了优缺点,引用[4]讲了Spring的选择机制。所以综合这些信息,应该能覆盖用户的问题。注意引用标识要放在对应的位置,比如在提到Spring默认行为时加上[^4],提到代理对象类型时引用[1]等。</think>### JDK动态代理CGLIB动态代理对比 #### 1. **实现原理** - **JDK动态代理**:基于Java反射机制,通过`Proxy`类生成代理对象,要求目标对象必须实现接口。代理类通过`InvocationHandler`接口实现方法拦截[^1][^3]。 - **CGLIB动态代理**:基于字节码操作(ASM框架),通过继承目标类生成子类代理。即使目标类未实现接口,也能创建代理。 #### 2. **代理对象类型** - **JDK动态代理**:只能代理接口,无法代理未实现接口的类[^3][^4]。 - **CGLIB动态代理**:可代理普通类,但对`final`类或方法无法代理[^4]。 #### 3. **依赖与兼容性** - **JDK动态代理**:无需额外依赖,仅依赖JDK原生API[^3]。 - **CGLIB动态代理**:需引入CGLIB库(如`cglib-nodep`)。 #### 4. **性能对比** - **生成代理速度**:JDK动态代理更快(直接生成字节码)[^3]。 - **方法调用速度**:CGLIB代理的方法调用通常更快(通过FastClass机制直接访问方法,无需反射)[^3]。 #### 5. **适用场景** - **JDK动态代理**:适合代理接口或已有接口实现的类(如Spring AOP默认对接口使用JDK代理)[^4]。 - **CGLIB动态代理**:适合代理无接口的类,或需要更高性能的场景(可通过Spring配置强制启用)。 #### 6. **限制** - **JDK动态代理**:无法绕过接口限制。 - **CGLIB动态代理**:无法代理`final`类或方法;需要处理构造函数(代理类会调用父类默认构造函数)[^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值