美文网首页spring framework
javassist动态代理与cglib动态代理

javassist动态代理与cglib动态代理

作者: Lnstark | 来源:发表于2021-12-19 15:45 被阅读0次

    mybatis的懒加载是用到了javassist的动态代理,所以想先简单说一下这个,顺便带上cglib动态代理。

    javassist动态代理

    这里我用的依赖

    <dependency>
        <groupId>org.javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.21.0-GA</version>
    </dependency>
    

    测试代码:

    package lnstark.test.testjavassistproxy;
    
    import javassist.NotFoundException;
    import javassist.util.proxy.MethodHandler;
    import javassist.util.proxy.ProxyFactory;
    
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    /**
     * by Lnstark
     * 2021/12/18
     */
    public class MyProxyFactory implements MethodHandler {
    
        private Object target;
    
        public MyProxyFactory(Object target) {
            this.target = target;
        }
    
        /**
         * 增强方法
         *
         * @param self 代理后的类
         * @param thisMethod 代理类的tweet方法
         * @param proceed 代理类的_d8tweet方法
         * @param args 方法参数
         * @return 执行结果
         */
        @Override
        public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
            System.out.println("before invoke");
            // 还记得jdk动态代理这里的传参会是target
            Object ret = proceed.invoke(self, args);
            System.out.println("after invoke");
            return ret;
        }
    
        static class Bird {
            private String name;
            public Bird(String name) {
                this.name = name;
            }
            void tweet() {
                System.out.println("my name is: " + name);
            }
        }
    
        public static void main(String[] args) throws IOException, NotFoundException {
            Bird bird = new Bird("百灵");
            Bird proxy = null;
            ProxyFactory enhancer = new ProxyFactory();
            // 设置代理类输出路径,实际的目录还要带上包名
            // 如此类的包名为lnstark.test.testjavassistproxy
            // 那生成的.class文件所在目录为 d:/lnstark/test/testjavassistproxy
            enhancer.writeDirectory = "d:/";
            // 需要代理的类
            enhancer.setSuperclass(Bird.class);
            try {
                // 生成代理对象
                proxy = (Bird) enhancer.create(new Class[]{String.class}, new Object[]{"布谷"}, new MyProxyFactory(bird));
            } catch (NoSuchMethodException | InstantiationException
                    | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
            
            proxy.tweet();
        }
    }
    

    执行结果:

    before invoke
    my name is: 布谷
    after invoke
    

    编译后的动态代理.class文件丢到idea里:

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package lnstark.test.testjavassistproxy;
    
    import java.io.ObjectStreamException;
    import java.lang.reflect.Method;
    import javassist.util.proxy.MethodHandler;
    import javassist.util.proxy.ProxyObject;
    import javassist.util.proxy.RuntimeSupport;
    import lnstark.test.testjavassistproxy.MyProxyFactory.Bird;
    
    public class MyProxyFactory$Bird_$$_jvstae2_0 extends Bird implements ProxyObject {
        private MethodHandler handler;
        public static byte[] _filter_signature;
        public static final long serialVersionUID;
        private static Method[] _methods_;
    
        public MyProxyFactory$Bird_$$_jvstae2_0(String var1) {
            this.handler = RuntimeSupport.default_interceptor;
            super(var1);
        }
    
        public final Object _d0clone() throws CloneNotSupportedException {
            return super.clone();
        }
    
        protected final Object clone() throws CloneNotSupportedException {
            Method[] var1 = _methods_;
            return (Object)this.handler.invoke(this, var1[0], var1[1], new Object[0]);
        }
    
        public final boolean _d1equals(Object var1) {
            return super.equals(var1);
        }
    
        public final boolean equals(Object var1) {
            Method[] var2 = _methods_;
            return (Boolean)this.handler.invoke(this, var2[2], var2[3], new Object[]{var1});
        }
    
        public final void _d2finalize() throws Throwable {
            super.finalize();
        }
    
        protected final void finalize() throws Throwable {
            Method[] var1 = _methods_;
            this.handler.invoke(this, var1[4], var1[5], new Object[0]);
        }
    
        public final int _d4hashCode() {
            return super.hashCode();
        }
    
        public final int hashCode() {
            Method[] var1 = _methods_;
            return (Integer)this.handler.invoke(this, var1[8], var1[9], new Object[0]);
        }
    
        public final String _d7toString() {
            return super.toString();
        }
    
        public final String toString() {
            Method[] var1 = _methods_;
            return (String)this.handler.invoke(this, var1[14], var1[15], new Object[0]);
        }
    
        public final void _d8tweet() {
            super.tweet();
        }
    
        final void tweet() {
            Method[] var1 = _methods_;
            this.handler.invoke(this, var1[16], var1[17], new Object[0]);
        }
    
        static {
            Method[] var0 = new Method[24];
            Class var1 = Class.forName("lnstark.test.testjavassistproxy.MyProxyFactory$Bird_$$_jvstae2_0");
            RuntimeSupport.find2Methods(var1, "clone", "_d0clone", 0, "()Ljava/lang/Object;", var0);
            RuntimeSupport.find2Methods(var1, "equals", "_d1equals", 2, "(Ljava/lang/Object;)Z", var0);
            RuntimeSupport.find2Methods(var1, "finalize", "_d2finalize", 4, "()V", var0);
            RuntimeSupport.find2Methods(var1, "hashCode", "_d4hashCode", 8, "()I", var0);
            RuntimeSupport.find2Methods(var1, "toString", "_d7toString", 14, "()Ljava/lang/String;", var0);
            RuntimeSupport.find2Methods(var1, "tweet", "_d8tweet", 16, "()V", var0);
            _methods_ = var0;
            serialVersionUID = -1L;
        }
    
        public void setHandler(MethodHandler var1) {
            this.handler = var1;
        }
    
        public MethodHandler getHandler() {
            return this.handler;
        }
    
        Object writeReplace() throws ObjectStreamException {
            return RuntimeSupport.makeSerializedProxy(this);
        }
    }
    

    find2Methods方法:

    public static void find2Methods(Class clazz, String superMethod,
                                    String thisMethod, int index,
                                    String desc, java.lang.reflect.Method[] methods)
    {
        methods[index + 1] = thisMethod == null ? null
                                                : findMethod(clazz, thisMethod, desc);
        methods[index] = findSuperClassMethod(clazz, superMethod, desc);
    }
    

    可以看出tweet是_methods_[16],_d8tweet是_methods_[17]。
    代理类调用tweet方法,里面调用handler.invoke(即我们实现的方法)。
    传入参数:代理类本身,tweet方法,_d8tweet方法和方法参数。

    cglib动态代理

    引入包:

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.3.0</version>
    </dependency>
    

    测试代码:

    package lnstark.test.testcglibproxy;
    
    import net.sf.cglib.core.DebuggingClassWriter;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    /**
     * by Lnstark
     * 2021/12/19
     */
    public class CglibProxy {
    
        static class Bird {
            private String name;
            public Bird(String name) {
                this.name = name;
            }
            void tweet() {
                System.out.println("my name is: " + name);
            }
        }
        static class MyInterceptor implements MethodInterceptor {
    
            /**
             *
             * @param o 代理后的对象
             * @param method Bird的原方法
             * @param objects 方法参数
             * @param methodProxy
             * @return 方法返回
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
                System.out.println("before invoke " + method.getName());
                // 这里用methodProxy而不是原始方法method
                Object ret = methodProxy.invokeSuper(o, objects);
                System.out.println("after invoke " + method.getName());
                return ret;
            }
        }
    
        public static void main(String[] args) {
            Bird bird = new Bird("百灵");
            // 指定生成的.class文件目录
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:/");
            // 生成的步骤类似javassist
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(Bird.class);
            enhancer.setCallback(new MyInterceptor());
            Bird proxy = (Bird) enhancer.create(new Class[]{String.class}, new Object[]{"布谷"});
            proxy.tweet();
        }
    }
    

    结果:

    before invoke tweet
    my name is: 布谷
    after invoke tweet
    

    代理类里会生成下面两个方法,tweet方法里调用我们实现的intercept方法,里面执行了methodProxy.invokeSuper(o, objects);底层是调用的这里的CGLIB$tweet$0方法。

    final void CGLIB$tweet$0() {
        super.tweet();
    }
    
    final void tweet() {
        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$tweet$0$Method, CGLIB$emptyArgs, CGLIB$tweet$0$Proxy);
        } else {
            super.tweet();
        }
    }
    

    相关文章

      网友评论

        本文标题:javassist动态代理与cglib动态代理

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