【Spring -- 11 cglib代理(Enhancer )】

cglib代理和 jdk 动态代理原理查不多

对比一下 CGLIB 代理和 JDK 动态代理的原理

  1. 回调接口的差异

    • JDK 动态代理使用的回调接口是 InvocationHandler
    • CGLIB 代理使用的回调接口是 MethodInterceptor
  2. 调用目标的差异

    • jdk, cglib 使用 method.invoke() 进行反射调用
       要调用足够次数才会进行优化
    • cglib使用 methodProxy.invoke(obj, args) 进行不反射调用
      这种方式可以直接调用到目标对象的方法,性能相对更好
      Spring 框架采用这种方式
    • cglib使用 methodProxy.invokeSuper(proxy, args) 进行不反射调用
      这种方式可以直接调用到代理对象的方法,可以省略目标对象

 cglib代理

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

import java.lang.reflect.Method;

public class CglibProxyExample {
    public static void main(String[] args) {
        Ia proxy = (Ia) Enhancer.create(Ia.class, new MethodInterceptorImpl());
        proxy.doSomething();
    }

    private static class MethodInterceptorImpl implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("Before method invocation: " + method.getName());
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("After method invocation: " + method.getName());
            return result;
        }
    }

    interface Ia {
        void doSomething();
    }

    static class IaImpl implements Ia {
        @Override
        public void doSomething() {
            System.out.println("Doing something...");
        }
    }
}

 FastClass

public abstract class FastClass {
    private Class type;

    protected FastClass() {
        throw new Error("Using the FastClass empty constructor--please report to the cglib-devel mailing list");
    }

    protected FastClass(Class type) {
        this.type = type;
    }
// .....

    public abstract int getIndex(String name, Class[] parameterTypes);

    public abstract int getIndex(Class[] parameterTypes);

    public abstract Object invoke(int index, Object obj, Object[] args) throws InvocationTargetException;

    public abstract Object newInstance(int index, Object[] args) throws InvocationTargetException;

    public abstract int getIndex(Signature sig);

    public abstract int getMaxIndex();

// .....

}

 

cglib 避免反射调用

  1. 当调用 MethodProxy 的 invoke 或 invokeSuper 方法时, 会动态生成两个类,会实现上述的抽象方法
           例如:

    • ProxyFastClass 配合代理对象一起使用, 避免反射

    • TargetFastClass 配合目标对象一起使用, 避免反射 (Spring 用的这种)

  2. TargetFastClass 记录了 Target 中方法与编号的对应关系
    假如有如下三个方法:

    • save(long) 编号 2

    • save(int) 编号 1

    • save() 编号 0

    • 首先根据方法名和参数个数、类型, 用 switch 和 if 找到这些方法编号

    • 然后再根据编号去调用目标方法, 又用了一大堆 switch 和 if, 但避免了反射

  3. ProxyFastClass 记录了 Proxy 中方法与编号的对应关系,不过 ProxyFastClass 额外提供了下面几个方法

    • saveSuper(long) 编号 2,不增强,仅是调用 super.save(long)

    • saveSuper(int) 编号 1,不增强, 仅是调用 super.save(int)

    • saveSuper() 编号 0,不增强, 仅是调用 super.save()

    • 查找方式与 TargetFastClass 类似

  4. 为什么有这么麻烦的一套东西呢?

    • 避免反射, 提高性能, 代价是一个代理类配两个 FastClass 类, 代理类中还得增加仅调用 super 的一堆方法

    • 用编号处理方法对应关系比较省内存, 另外, 最初获得方法顺序是不确定的, 这个过程没法固定死

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值