CGlib动态代理进阶

和 jdk 动态代理原理查不多

  1. 回调的接口换了一下,InvocationHandler 改成了 MethodInterceptor

  2. 调用目标时有所改进,见下面代码片段

    1. method.invoke 是反射调用,必须调用到足够次数才会进行优化

    2. methodProxy.invoke 是不反射调用,它会正常(间接)调用目标对象的方法(Spring 采用)

    3. methodProxy.invokeSuper 也是不反射调用,它会正常(间接)调用代理对象的方法,可以省略目标对象

版本1.0使用jdk代理思路实现

package com.butch.a13;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class A13 {
    public static void main(String[] args) {
        Proxy proxy = new Proxy();
        Target target = new Target();
        proxy.setMethodInterceptor(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("======before cglib=================");
                return method.invoke(target,objects);
            }
        });
        proxy.save();
        proxy.save(1);
        proxy.save(2L);
    }
}
package com.butch.a13;

import org.springframework.cglib.proxy.MethodInterceptor;

import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;

//代理类
public class Proxy extends Target {

    //cglib代理的实现器
    private MethodInterceptor methodInterceptor;

    public void setMethodInterceptor(MethodInterceptor methodInterceptor){
        this.methodInterceptor = methodInterceptor;
    }

    static Method method1;
    static Method method2;
    static Method method3;
    static{
        try {
            method1 = Target.class.getMethod("save");
            method2 = Target.class.getMethod("save",int.class);
            method3 = Target.class.getMethod("save",long.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void save() {
        try {
            methodInterceptor.intercept(this,method1,new Object[0],null);
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public void save(int i) {
        try {
            methodInterceptor.intercept(this,method2,new Object[]{i},null);
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public void save(long j) {
        try {
            methodInterceptor.intercept(this,method3,new Object[]{j},null);
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}

 

package com.butch.a13;

public class Target {

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

    public void save(int i) {
        System.out.println("save(int)");
    }

    public void save(long j) {
        System.out.println("save(long)");
    }
}

 和jdk的区别:解耦接口MethodInterceptor成员变量,通过set方法设置,而不是成员变量

版本2.0methodproxy避免反射调用

使用methodproxy增强,内部无反射

package com.butch.a13;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class A13 {
    public static void main(String[] args) {
        Proxy proxy = new Proxy();
        Target target = new Target();
        proxy.setMethodInterceptor(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("======before cglib=================");
//                return method.invoke(target,objects);
                //2.0使用methodproxy
                //基于目标类
//                return methodProxy.invoke(target,objects);
                //基于代理类
                return methodProxy.invokeSuper(o,objects);
            }
        });
        proxy.save();
        proxy.save(1);
        proxy.save(2L);
    }
}
package com.butch.a13;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;

//目标类
public class Proxy extends Target {

    //cglib代理的实现器
    private MethodInterceptor methodInterceptor;

    public void setMethodInterceptor(MethodInterceptor methodInterceptor){
        this.methodInterceptor = methodInterceptor;
    }

    static Method method1;
    static Method method2;
    static Method method3;
    static MethodProxy save0;
    static MethodProxy save1;
    static MethodProxy save2;
    static{
        try {
            method1 = Target.class.getMethod("save");
            method2 = Target.class.getMethod("save",int.class);
            method3 = Target.class.getMethod("save",long.class);
            //版本2.0
            save0 = MethodProxy.create(Target.class,Proxy.class,"()V","save","saveSuper");
            save1 = MethodProxy.create(Target.class,Proxy.class,"(I)V","save","saveSuper");
            save2 = MethodProxy.create(Target.class,Proxy.class,"(J)V","save","saveSuper");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }



    //=================> 带原始功能的方法
    public void saveSuper(){
        super.save();
    }
    public void saveSuper(int i){
        super.save(i);
    } public void saveSuper(long j){
        super.save(j);
    }


    //>>>>>>>>>>>>带增强功能的方法
    @Override
    public void save() {
        try {
            methodInterceptor.intercept(this,method1,new Object[0],save0);
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public void save(int i) {
        try {
            methodInterceptor.intercept(this,method2,new Object[]{i},save1);
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public void save(long j) {
        try {
            methodInterceptor.intercept(this,method3,new Object[]{j},save2);
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}

methodproxy避免反射原理

生成两个fastclass代理类,一个目标类的,一个代理类的

TargetFastClass本质上仍旧是一个代理类,

首先当创建代理类的methodproxy方法时候,会根据方法签名获取到目标方法的编号,

然后当执行的invoke代理方法的时候,会根据目标方法编号,去使用target对象直接调用对应的方法

  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 中方法与编号的对应关系,不过 Proxy 额外提供了下面几个方法

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

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

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

    • 查找方式与 TargetFastClass 类似

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

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

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

package com.butch.a13;

import org.springframework.cglib.core.Signature;


//创建代理对象 创建methodproxy的create时生成
public class TargetFastClass {

    //用于匹配传递方法签名
    static Signature s0 = new Signature("save","V()");
    static Signature s1 = new Signature("save","V(I)");
    static Signature s2 = new Signature("save","V(J)");


    // 获取目标方法的编号
    /*
        Target
            save()              0
            save(int)           1
            save(long)          2
        signature 包括方法名字、参数返回值
        根据方法签名信息获取方法的变编号
     */
    public int getIndex(Signature signature) {
        if (s0.equals(signature)) {
            return 0;
        }
        if (s1.equals(signature)) {
            return 1;
        }if (s2.equals(signature)) {
            return 2;
        }
        return -1;
    }

    // 根据getindex返回的方法编号, 正常无反射调用目标对象方法
    public Object invoke(int index, Object target, Object[] args) {
        if (index == 0){
            Target target1 = (Target) target;
            target1.save();
            return null;
        }
        if (index == 1){
            Target target1 = (Target) target;
            target1.save((int)(args[0]));
            return null;
        }
        if (index == 2){
            Target target1 = (Target) target;
            target1.save((long)(args[0]));
            return null;
        }
        throw new RuntimeException("do not invoke!");
    }
    

}

ProxyFastClass的实现逻辑和target类似,但是要使用代理类中的调用真实方法进行编号

package com.butch.a13;

import org.springframework.cglib.core.Signature;

public class ProxyFastClass {
    //用于匹配传递方法签名
    static Signature s0 = new Signature("saveSuper","V()");
    static Signature s1 = new Signature("saveSuper","V(I)");
    static Signature s2 = new Signature("saveSuper","V(J)");


    // 获取目标方法的编号
    /*
        Target
            save()              0
            save(int)           1
            save(long)          2
        signature 包括方法名字、参数返回值
        根据方法签名信息获取方法的变编号
     */
    public int getIndex(Signature signature) {
        if (s0.equals(signature)) {
            return 0;
        }
        if (s1.equals(signature)) {
            return 1;
        }if (s2.equals(signature)) {
            return 2;
        }
        return -1;
    }

    // 根据getindex返回的方法编号, 正常无反射调用目标对象方法
    public Object invoke(int index, Object target, Object[] args) {
        if (index == 0){
            Proxy target1 = (Proxy) target;
            target1.saveSuper();
            return null;
        }
        if (index == 1){
            Proxy target1 = (Proxy) target;
            target1.saveSuper((int)(args[0]));
            return null;
        }
        if (index == 2){
            Proxy  target1 = (Proxy) target;
            target1.saveSuper((long)(args[0]));
            return null;
        }
        throw new RuntimeException("do not invoke!");
    }

    public static void main(String[] args) {
        //模拟实现
        ProxyFastClass proxyFastClass = new ProxyFastClass();
        int index = proxyFastClass.getIndex(new Signature("saveSuper", "V()"));
        System.out.println("index = " + index);
        proxyFastClass.invoke(index,new Proxy() ,new Object[0]);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值