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>cglibgroupId>
    <artifactId>cglibartifactId>
    <version>2.2.2version>
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,第一时间收到更新内容。
JDK动态代理和CGlib代理的区别_第1张图片

你可能感兴趣的:(Java基础,java)