spring 13 cglib 避免反射调用 MethodProxy 原理

cglib 如何避免反射

点击查看模拟代码


/**
 * 模拟 methodProxy invoke() 方法调用生成的代理类,和代理对象配合使用
 * 为什么类名是 FastClass 呢,因为动态生成的代理类的父接口就是它
 */
public class S13ProxyFastClass {

    private Signature ss1 = new Signature("ss120", "()V");
    private Signature ss2 = new Signature("ss121", "(I)V");
    private Signature ss3 = new Signature("ss122", "(II)V");


    // 获取代理方法的编号,编号可以随意,只要能区分即可
    /*
        Target
            save()              0
            save(int)           1
            save(int,int)       2
        signature 包括方法名字、参数返回值 不存在返回 -1
     */
    public int getIndex(Signature signature) {
        if (ss1.equals(signature)) {
            return 1;
        } else if (ss2.equals(signature)) {
            return 3;
        } else if (ss3.equals(signature)) {
            return 5;
        }
        return -1;
    }

    /**
     * 根据方法编号,调用目标对象的方法
     */
    public Object invoke(int index, Object proxy, Object[] args) {
        if (index == 1) {
            ((S12Proxy) proxy).ss120();
            return null; // 无返回值返回 null
        } else if (index == 3) {
            ((S12Proxy) proxy).ss121((int) args[0]);
            return null;

        } else if (index == 5) {
            ((S12Proxy) proxy).ss122((int) args[0], (int) args[1]);
            return null;

        } else {
            throw new RuntimeException("无此方法");
        }
    }
}

/**
 * methodProxy  invoke() 方法调用时生成的代理类,配合目标对象使用
 */
public class S13TargetFastClass {


    private Signature s1 = new Signature("s120", "()V");
    private Signature s2 = new Signature("s121", "(I)V");
    private Signature s3 = new Signature("s122", "(II)V");


    // 获取目标方法的编号,编号可以随意,只要能区分即可
    /*
        Target
            save()              0
            save(int)           1
            save(long)          2
        signature 包括方法名字、参数返回值 不存在返回 -1
     */
    public int getIndex(Signature signature) {
        if (s1.equals(signature)) {
            return 0;
        } else if (s2.equals(signature)) {
            return 1;
        } else if (s3.equals(signature)) {
            return 2;
        }
        return -1;
    }

    /**
     * 根据方法编号,调用目标对象的方法
     */
    public Object invoke(int index, Object target, Object[] args) {
        if (index == 0) {
            ((S12Target) target).s120();
            return null; // 无返回值返回 null
        } else if (index == 1) {
            ((S12Target) target).s121((int) args[0]);
            return null;

        } else if (index == 2) {
            ((S12Target) target).s122((int) args[0], (int) args[1]);
            return null;

        } else {
            throw new RuntimeException("无此方法");
        }
    }

}

//测试
 public static void main(String[] args) {

        testTargetFastClass(new Signature("s120", "()V"));
        testProxyFastClass(new Signature("ss120", "()V"), new Object[]{});
        testProxyFastClass(new Signature("ss122", "(II)V"), new Object[]{1,3});

    }

    private static void testTargetFastClass(Signature s) {
        S13TargetFastClass fastClass = new S13TargetFastClass();
        int index = fastClass.getIndex(s);
        fastClass.invoke(index, new S12Target(), new Object[]{});
    }
    private static void testProxyFastClass(Signature s, Object[] args) {
        S13ProxyFastClass fastClass = new S13ProxyFastClass();
        int index = fastClass.getIndex(s);
        fastClass.invoke(index, new S12Proxy(), args);
    }
点击查看 methodProxy 源代码
package org.springframework.cglib.proxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.springframework.cglib.core.AbstractClassGenerator;
import org.springframework.cglib.core.CodeGenerationException;
import org.springframework.cglib.core.GeneratorStrategy;
import org.springframework.cglib.core.NamingPolicy;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastClass.Generator;

public class MethodProxy {
    private Signature sig1;
    private Signature sig2;
    private MethodProxy.CreateInfo createInfo;
    private final Object initLock = new Object();
    private volatile MethodProxy.FastClassInfo fastClassInfo;

    public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
        MethodProxy proxy = new MethodProxy();
        proxy.sig1 = new Signature(name1, desc);
        proxy.sig2 = new Signature(name2, desc);
        proxy.createInfo = new MethodProxy.CreateInfo(c1, c2);
        return proxy;
    }

    private void init() {
        if (this.fastClassInfo == null) {
            synchronized(this.initLock) {
                if (this.fastClassInfo == null) {
                    MethodProxy.CreateInfo ci = this.createInfo;
                    MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
                    fci.f1 = helper(ci, ci.c1);
                    fci.f2 = helper(ci, ci.c2);
                    fci.i1 = fci.f1.getIndex(this.sig1);
                    fci.i2 = fci.f2.getIndex(this.sig2);
                    this.fastClassInfo = fci;
                    this.createInfo = null;
                }
            }
        }

    }

    private static FastClass helper(MethodProxy.CreateInfo ci, Class type) {
        Generator g = new Generator();
        g.setType(type);
        g.setContextClass(type);
        g.setClassLoader(ci.c2.getClassLoader());
        g.setNamingPolicy(ci.namingPolicy);
        g.setStrategy(ci.strategy);
        g.setAttemptLoad(ci.attemptLoad);
        return g.create();
    }

    private MethodProxy() {
    }

    public Signature getSignature() {
        return this.sig1;
    }

    public String getSuperName() {
        return this.sig2.getName();
    }

    public int getSuperIndex() {
        this.init();
        return this.fastClassInfo.i2;
    }

    FastClass getFastClass() {
        this.init();
        return this.fastClassInfo.f1;
    }

    FastClass getSuperFastClass() {
        this.init();
        return this.fastClassInfo.f2;
    }

    public static MethodProxy find(Class type, Signature sig) {
        try {
            Method m = type.getDeclaredMethod("CGLIB$findMethodProxy", MethodInterceptorGenerator.FIND_PROXY_TYPES);
            return (MethodProxy)m.invoke((Object)null, sig);
        } catch (NoSuchMethodException var3) {
            throw new IllegalArgumentException("Class " + type + " does not use a MethodInterceptor");
        } catch (InvocationTargetException | IllegalAccessException var4) {
            throw new CodeGenerationException(var4);
        }
    }

    public Object invoke(Object obj, Object[] args) throws Throwable {
        try {
            this.init();
            MethodProxy.FastClassInfo fci = this.fastClassInfo;
            return fci.f1.invoke(fci.i1, obj, args);
        } catch (InvocationTargetException var4) {
            throw var4.getTargetException();
        } catch (IllegalArgumentException var5) {
            if (this.fastClassInfo.i1 < 0) {
                throw new IllegalArgumentException("Protected method: " + this.sig1);
            } else {
                throw var5;
            }
        }
    }

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

    private static class CreateInfo {
        Class c1;
        Class c2;
        NamingPolicy namingPolicy;
        GeneratorStrategy strategy;
        boolean attemptLoad;

        public CreateInfo(Class c1, Class c2) {
            this.c1 = c1;
            this.c2 = c2;
            AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
            if (fromEnhancer != null) {
                this.namingPolicy = fromEnhancer.getNamingPolicy();
                this.strategy = fromEnhancer.getStrategy();
                this.attemptLoad = fromEnhancer.getAttemptLoad();
            }

        }
    }

    private static class FastClassInfo {
        FastClass f1;
        FastClass f2;
        int i1;
        int i2;

        private FastClassInfo() {
        }
    }
}

  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 的一堆方法
    • 用编号处理方法对应关系比较省内存, 另外, 最初获得方法顺序是不确定的, 这个过程没法固定死
posted @ 2022-06-22 16:07  xy7112  阅读(292)  评论(0)    收藏  举报