美文网首页
Cglib和jdk动态代理的区别

Cglib和jdk动态代理的区别

作者: 宙斯是只猫 | 来源:发表于2019-08-11 02:16 被阅读0次

首先从实现上来讲,jdk动态代理是使用jdk自带的字节码技术去生成一个类,而cglib则基于asm,他两在使用上最直观的感受是,cglib不需要接口,而jdk需要接口,在性能上,下面的例子,jdk循环一万次执行耗时大概在150-170ms之间,而cglib则是300ms以上,所以jdk的性能是略优于asm的.

我们举两个例子,实践下二者的区别,一个是玩游戏的例子,在'游戏'两个字输出之前,用jdk代理输出'挂机'二字,另外一个例子是用的cglib,在用户类输出'买车'之前,我们用中间商那个类输出'赚差价'
jdk

public interface IGame {
    void play();
}


public class Agent implements InvocationHandler {


    public IGame game;


    public Agent(IGame game) {
        this.game = game;
    }

    public void agent(){
        System.out.println("挂机");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        agent();
        return method.invoke(game);
    }
}


public class Game implements IGame {
    @Override
    public void play() {
        System.out.println("游戏");
    }
}


cglib

public class Customer {


   public void buyCar(){
      System.out.println("买车");
   }
}


public class MiddleBussiness implements MethodInterceptor {


public void  makeMoney(){
      System.out.println("中间商赚差价");
}

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    makeMoney();
        return methodProxy.invokeSuper(o, objects);
    }
}

测试类


public class Main {


    public static void main(String[] args) {
            jdk();
         System.out.println("---------------");
         cglib();
    }



    public static void jdk(){
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        Game g = new Game();
        Agent agent = new Agent(g);
        IGame game = (IGame) Proxy.newProxyInstance(Game.class.getClassLoader(), new Class[]{IGame.class}, agent);
        game.play();

    }



    public static void cglib(){
       System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "d://cglib");
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Customer.class);
        enhancer.setCallback(new MiddleBussiness());
        Customer customer = (Customer) enhancer.create();
        customer.buyCar();
    }
}

二者的使用上除了对目标类要求是否有接口外还有一个区别就是对于目标对象的创建上,jdk需要手动创建目标对象,而cglib并不需要.

看一下二者生成的代理类是什么样的
Jdk


public final class $Proxy0 extends Proxy implements IGame {


    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final void play() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }




Cglib


public class Customer$$EnhancerByCGLIB$$7bd11a1d extends Customer implements Factory {


  final void CGLIB$buyCar$0() {
        super.buyCar();
    }

    public final void buyCar() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$buyCar$0$Method, CGLIB$emptyArgs, CGLIB$buyCar$0$Proxy);
        } else {
            super.buyCar();
        }
    }

可以从代码中看出新生成的类都是继承于原来的类,都是属于原来类的子类,甚至在接口调用中,二者都是讲将调用传递给了handler,不同点事jdk的处理是直接将当前代理类,方法和参数传递了过去,注意此处并没有传递目标对象,,而cglib则除了传递当前代理,方法以及参数,还多传递了个methodProxy,这个对象里面封装了参数签名的信息,并且提供了调用当前代理类父类的方法,那为啥jdk没有实现直接调用父类的方法呢,因为cglib调用父类的方法依赖于FastClass,而这个类的实现也是由cglib动态代理实现,调用如下:

 public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

FastClass的代理类实现,主要是根据fci.i2这一个int值来找对应的方法,我们的buyCar方法对应的值为16

public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        7bd11a1d var10000 = (7bd11a1d)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
           
            case 16:
                var10000.CGLIB$buyCar$0();
                return null;
      
       
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

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

看到这里有没有一种恍然大悟的感觉,这个methodProxy又去调用了代理类的CGLIB$buyCar$0这个方法,这个方法也是生成的里面只有一句话就是super.buyCar()从而调用了父类.

相关文章

  • JDK和CGLIB动态代理区别

    JDK和CGLIB动态代理区别 一 JDK和CGLIB动态代理原理1、JDK动态代理利用拦截器(拦截器必须实现In...

  • java动态代理

    目录: 简介 jdk动态代理 cglib动态代理 jdk动态代理与cglib的区别 应用spring的aop 简介...

  • Java面试之Java基础下册(含答案)

    15.动态代理与cglib实现的区别。 动态代理有两种实现方式,分别是:jdk动态代理和cglib动态代理 jdk...

  • 源码解析--JDK动态代理

    动态代理的两种方式JDK动态代理和cglib动态代理在上一篇中动态代理jdk和cglib的区别已经通过实例做了比较...

  • 设计模式等

    JDK和CGLIB生成动态代理类的区别

  • Java Spring中的动态代理cglib

    总结 JDK的动态代理和 Spring中的动态代理cglib区别 JDK 的动态代理 :针对实现了接口的类产生代理...

  • 编程常用的设计模式

    动态代理和静态代理 静态代理 动态代理 静态代理与动态代理的区别 JDK中的动态代理和CGLIB 实现动态代理的方...

  • JDK动态代理和CGLIB代理有什么区别?

    JDK动态代理和CGLIB代理有什么区别?JDK 动态代理主要是针对类实现了某个接口,AOP 则会使用 JDK 动...

  • SpringBoot动态代理配置说明

    SpringBoot动态代理配置说明 基于CGLIB的代理与基于JDK的动态代理实现的声明式事务的区别 CGLIB...

  • Spring AOP中的动态代理

    Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理: (3)静态代理与动态代理区别...

网友评论

      本文标题:Cglib和jdk动态代理的区别

      本文链接:https://www.haomeiwen.com/subject/pdfjjctx.html