JDK动态代理与cglib动态代理

JDK

Spring aop默认使用jdk动态代理。
jdk动态代理要求被代理对象是某个接口的实现类。为什么呢,先看一个简单的例子

//一个接口
public interface FoodService {
    void makeNoddles();
    void makeChicken();
}

//被代理对象的类(实现了接口)
public class FoodServiceImpl implements FoodService{
    @Override
    public void makeChicken() {
        System.out.println("chicken");
    }
    @Override
    public void makeNoddles() {
        System.out.println("noddles");
    }
}

//真正要写的类,实现JDK提供的InvocationHandler接口
public class ProxyFactory implements InvocationHandler {
	//被代理对象
    private Object target;
	//构造器
    public ProxyFactory(Object target){
        this.target=target;
    }
	//创建代理对象Proxy
    public Object createProxy(){
        ClassLoader classLoader=target.getClass().getClassLoader();
		//获取被代理对象所属类实现的接口
        Class<?>[] interfaces=target.getClass().getInterfaces();
	//从源码上看,newProxyInstance()这个方法必须要interfaces参数
        Object proxyInstance=Proxy.newProxyInstance(classLoader,interfaces,this);
        return proxyInstance;
    }
  	//必须重写invoke方法,可以在方法执行前后增加处理逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        Object invoke=method.invoke(target,args);
        System.out.println("after");
        return invoke;
    }}
    
//测试类
public class Test {
    public static void main(String[] args) {
        //被代理对象
        FoodServiceImpl f=new FoodServiceImpl();
        //传入被代理对象,创建工厂
        ProxyFactory proxyFactory=new ProxyFactory(f);
		//创建代理对象并转为被代理对象的接口类型
        FoodService foodService=(FoodService) proxyFactory.createProxy();
        //代理对象执行原方法,内部自动调用了ProxyFactory的invoke方法,实现了动态代理
        foodService.makeNoddles();
    }
}

从代码来看,jdk提供的动态代理使用比较简单,真正需要写的代码就是上面的ProxyFactory类,实现InvocationHandler并重写invoke方法就行,之所以要求被代理类有借口,因为本身设计是基于接口实现的,需要依靠接口创建代理对象。

public final class $Proxy0 extends Proxy implements HelloInterface{
.......

JDK动态代理动态生成的代理类,已经继承了Proxy,因为JAVA单继承,要获得被代理类的特性只能从实现接口的角度。

cglib

cglib基于第三方框架,采用字节码技术实现动态代理

public class CglibProxyFactory implements MethodInterceptor {
    private Object target;

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

    public Object createProxy(){
        Enhancer enhancer=new Enhancer();
		//传参 被代理类
        enhancer.setSuperclass(target.getClass());

        enhancer.setCallback(this);
        //返回代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib before");
        Object invoke= methodProxy.invoke(target,objects);
        System.out.println("cglib after");

        return invoke;
    }

    public static void main(String[] args) {
        FoodServiceImpl f=new FoodServiceImpl();

        CglibProxyFactory factory=new CglibProxyFactory(f);

        FoodServiceImpl foodService=(FoodServiceImpl) factory.createProxy();
        foodService.makeChicken();
    }
}

cglib动态代理创建代理对象只需要被代理类,不受接口限制,
因为在底层,cglib实现动态代理是在运行时依据字节码,动态生成被代理类的子类,并在子类中对原方法进行增强。是从继承的角度实现动态代理(所以被代理类不能被final,private修饰)。

效率

二者效率对比,从JDK1.8开始,JDK的动态代理执行速度要比cglib高,但是JDK动态代理有一定限制,就是被代理对象必须要有接口。而cglib适用任何情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值