JDK动态代理与CGLIB动态代理应用及源码解析

代理模式

代理模式:为其他对象提供一种代理以控制对这个对象的访问。

代理模式中有三种角色:Subject抽象主题角色、RealSubject真实主题角色、Proxy代理主题角色。Subject描述了业务行为,RealSubject执行具体的业务逻辑,Proxy代理会拦截对RealSubject对象方法的调用,并在方法调用前后做预处理以及一些善后工作。

代理模式可以很好地在不侵入原代码的情况下,拓展原来的功能。

下图为Proxy模式的静态类图:
这里写图片描述
下图为Proxy模式的调用关系:
这里写图片描述

动态代理

静态代理由于硬编码,难以应对真实对象和调用方法灵活多变的情况,动态代理则对这些场景应付自如。

动态代理主要有两种实现方式:1、JDK自带的Proxy 2、CGLIB字节码生成库

基于JDK的动态代理

基于JDK的动态代理关键在于两个类:InvocationHandler和Proxy。
其主要实现逻辑是,由InvocationHandler定义方法执行前后的增强逻辑,由Proxy类去生成一个继承自Proxy并且实现了真实对象接口的新对象–代理对象,对该代理对象的方法调用经由InvocationHandler拦截,执行增强逻辑和调用真实对象执行业务逻辑。

下面我们先看一个例子:
定义接口:

public interface UserService {
    public String getName(int id);

    public Integer getAge(int id);
}

定义真实对象:

public class UserServiceImpl implements UserService {

    public UserServiceImpl() {
    }

    @Override
    public String getName(int id) {
        System.out.println("---getName---");
        return "John";
    }

    @Override
    public Integer getAge(int id) {
        System.out.println("---getAge---");
        return 10;
    }

}

定义InvocationHandler:

public class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("getName")) {
            System.out.println("+++before get name+++");
            Object res = method.invoke(target, args);
            System.out.println("+++after get name+++");
            return res;
        } else {
            Object res = method.invoke(target, args);
            return res;
        }

    }

    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        UserService us = new UserServiceImpl();
        InvocationHandler ih = new MyInvocationHandler(us);
        UserService usProxy = (UserService) Proxy.newProxyInstance(us.getClass().getClassLoader(),
                us.getClass().getInterfaces(), ih);
        System.out.println(usProxy.getName(1));
        System.out.println(usProxy.getAge(1));
        System.out.println(usProxy.getClass());
    }

}

测试结果:
这里写图片描述

扫描二维码关注公众号,回复: 1433472 查看本文章

可以看到,对于getName方法的增强逻辑执行了。

下面我们从源码角度分析一下这个过程的实现原理,先看InvocationHandler:
InvocationHandler是一个接口,只有一个方法:

 public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

在定义增强逻辑类时,需要实现该接口,并在invoke方法里实现增强逻辑和对真实对象方法的调用。对于invoke方法的三个参数,proxy表示代理对象,method表示真实对象的方法,args表示真实对象方法的参数,这里也可以看出对真实对象方法的调用是通过反射来实现的。

增强逻辑定义好了以后,我们需要一个代理对象来执行,先看如何产生这个代理对象。代理对象的产生是通过调用Proxy类的静态方法:newProxyInstance,以下源码分析部分篇幅原因仅截取部分代码片段。

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
        //该方法需要三个参数:ClassLoader确保返回的代理对象和真实对象由同一个类

        加载器加载,interfaces用于定义代理类应该实现的方法,
        invocationHandler用于定义代理类的增强逻辑
    {
        if (h == null) {
            throw new NullPointerException();
        }

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
         //这一行代码很关键,这里是获取代理对象Class对象,Proxy类内部维护了代理
         //对象的缓存,如果缓存里有则直接返回,如果没有,则生成它
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            //由Class对象获取构造器
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
                // create proxy instance with doPrivilege as the proxy class may
                // implement non-public interfaces that requires a special permission
                return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                    public Object run() {
                        return newInstance(cons, ih);
                    }
                });
            } else {
                //最后由构造器返回新的代理对象实例
                return newInstance(cons, ih);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString());
        }
    }

接下来我们看代理对象的Class对象是如何生成的,缓存逻辑略去不表,直接看没有缓存的情况,代理类Class对象由ProxyClassFactory工厂生成:

private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();
       //验证代码略去
            /*
             * Generate the specified proxy class.
             */
             //这里生成了代理对象二进制字节码流
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces);
            try {
                //通过二进制字节码流加载代理类
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

最终生成二进制字节码流用到了Sun的ProxyGenerator类,反编译:

public static byte[] generateProxyClass(String s, Class aclass[])
    {
        ProxyGenerator proxygenerator = new ProxyGenerator(s, aclass);
        //该方法生成代理对象的二进制字节码流
        byte abyte0[] = proxygenerator.generateClassFile();
        //如果要保存该字节码文件,可以将其写到硬盘上,我们稍后分析
        if(saveGeneratedFiles)
            //保存文件部分略去
        return abyte0;
    }

具体生成源码如下:

private byte[] generateClassFile() {
        addProxyMethod(hashCodeMethod, java / lang / Object);
        addProxyMethod(equalsMethod, java / lang / Object);
        addProxyMethod(toStringMethod, java / lang / Object);
        for (int i = 0; i < interfaces.length; i++) {
            Method amethod[] = interfaces[i].getMethods();
            for (int k = 0; k < amethod.length; k++)
                addProxyMethod(amethod[k], interfaces[i]);

        }

        List list;
        for (Iterator iterator = proxyMethods.values().iterator(); iterator.hasNext(); checkReturnTypes(list))
            list = (List) iterator.next();

        try {
            methods.add(generateConstructor());
            for (Iterator iterator1 = proxyMethods.values().iterator(); iterator1.hasNext();) {
                List list1 = (List) iterator1.next();
                Iterator iterator2 = list1.iterator();
                while (iterator2.hasNext()) {
                    ProxyMethod proxymethod = (ProxyMethod) iterator2.next();
                    fields.add(new FieldInfo(proxymethod.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                    methods.add(proxymethod.generateMethod());
                }
            }

            methods.add(generateStaticInitializer());
        } catch (IOException ioexception) {
            throw new InternalError("unexpected I/O Exception");
        }
        if (methods.size() > 65535)
            throw new IllegalArgumentException("method limit exceeded");
        if (fields.size() > 65535)
            throw new IllegalArgumentException("field limit exceeded");
        cp.getClass(dotToSlash(className));
        cp.getClass("java/lang/reflect/Proxy");
        for (int j = 0; j < interfaces.length; j++)
            cp.getClass(dotToSlash(interfaces[j].getName()));

        cp.setReadOnly();
        ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
        DataOutputStream dataoutputstream = new DataOutputStream(bytearrayoutputstream);
        try {
            dataoutputstream.writeInt(-889275714);
            dataoutputstream.writeShort(0);
            dataoutputstream.writeShort(49);
            cp.write(dataoutputstream);
            dataoutputstream.writeShort(49);
            dataoutputstream.writeShort(cp.getClass(dotToSlash(className)));
            dataoutputstream.writeShort(cp.getClass("java/lang/reflect/Proxy"));
            dataoutputstream.writeShort(interfaces.length);
            for (int l = 0; l < interfaces.length; l++)
                dataoutputstream.writeShort(cp.getClass(dotToSlash(interfaces[l].getName())));

            dataoutputstream.writeShort(fields.size());
            FieldInfo fieldinfo;
            for (Iterator iterator3 = fields.iterator(); iterator3.hasNext(); fieldinfo.write(dataoutputstream))
                fieldinfo = (FieldInfo) iterator3.next();

            dataoutputstream.writeShort(methods.size());
            MethodInfo methodinfo;
            for (Iterator iterator4 = methods.iterator(); iterator4.hasNext(); methodinfo.write(dataoutputstream))
                methodinfo = (MethodInfo) iterator4.next();

            dataoutputstream.writeShort(0);
        } catch (IOException ioexception1) {
            throw new InternalError("unexpected I/O Exception");
        }
        return bytearrayoutputstream.toByteArray();
    }

至此,总结一下,Proxy类通过ProxyClassFactory生成了继承Proxy类并实现了真实对象接口的 $ProxyX代理对象的二进制字节码流,并加载该字节码返回代理对象Class对象,由该Class对象经反射得到构造器构造了代理对象的实例。
在源码中我们可以通过saveGeneratedFiles变量保存生成的class文件,我们反编译上面的示例生成的class文件:

public final class $Proxy0 extends Proxy implements UserService {

    private static Method m1;
    private static Method m4;
    private static Method m0;
    private static Method m3;
    private static Method m2;

    public $Proxy0(InvocationHandler invocationhandler) {
        super(invocationhandler);
    }

    public final boolean equals(Object obj) {
        try {
            return ((Boolean) super.h.invoke(this, m1, new Object[]{obj})).booleanValue();
        } catch (Error _ex) {
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
//这里是UserService接口的getAge方法,在代理对象$Proxy0上的调用被invocationHandler拦截,
//经由其invoke方法调用(即我们之前定义的MyinvocationHandler的invoke方法),
//留意invoke方法的参数,我们在MyinvocationHandler里定义invoke方法时并没有使用proxy参数,
//这里proxy参数的位置传入了this变量,即代理对象本身。
    public final Integer getAge(int i) {
        try {
            return (Integer) super.h.invoke(this, m4, new Object[]{Integer.valueOf(i)});
        } catch (Error _ex) {
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode() {
        try {
            return ((Integer) super.h.invoke(this, m0, null)).intValue();
        } catch (Error _ex) {
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String getName(int i) {
        try {
            return (String) super.h.invoke(this, m3, new Object[]{Integer.valueOf(i)});
        } catch (Error _ex) {
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString() {
        try {
            return (String) super.h.invoke(this, m2, null);
        } catch (Error _ex) {
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m4 = Class.forName("cn.john.test.dynamicProxy.UserService").getMethod("getAge", new Class[]{Integer.TYPE});
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            m3 = Class.forName("cn.john.test.dynamicProxy.UserService").getMethod("getName", new Class[]{Integer.TYPE});
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
        } catch (NoSuchMethodException nosuchmethodexception) {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        } catch (ClassNotFoundException classnotfoundexception) {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
        }
    }
}

基于CGLIB的动态代理

使用示例

public class UserServiceB {
    public String getName(int id) {
        System.out.println("---getName---");
        return "John";
    }
    public Integer getAge(int id) {
        System.out.println("---getAge---");
        return 10;
    }
    public static void main(String[] args) throws InterruptedException, IOException {
    //将cglib生成的Class对象写成文件存入硬盘,后面反编译出来用以分析
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
        UserServiceB us = new UserServiceB();
        // 定义增强器
        Enhancer en = new Enhancer();
        // 定义要代理的对象
        en.setSuperclass(us.getClass());
        // 定义回调函数
        en.setCallback(new MethodInterceptor() {
            //这里要理解intercept方法的几个参数代表的意思
            //obj指的是代理类对象
            //Method指的是 目标类中被拦截的方法
            //args指的是 调用拦截方法所需的参数
            //MethodProxy指的是用来调用目标类被拦截方法的方法,这个方法比反射更快
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy)
                    throws Throwable {
                System.out.println("-----before-------");
                //这里只能用invokeSuper,原因稍后解释
                methodProxy.invokeSuper(obj, args);
                System.out.println("-----after--------");
                return null;
            }

        });
        // 生成代理对象
        UserServiceB usb = (UserServiceB) en.create();
        // 在代理对象上调用方法
        usb.getName(1);

    }

}

运行结果:
这里写图片描述

同时生成了三个class文件:一个是代理类,一个是代理类的FastClass,一个是目标类的FastClass
这里写图片描述

源码分析

代理类源码概览

从上面的示例代码中,我们知道通过cglib生成代理类只需要一个目标类和一个回调函数(增强逻辑),下面我们从在代理对象上调用getName()方法出发,一步一步分析cglib动态代理的实现原理。

先来看生成的代理对象Class文件反编译后的源码(代码很长,代理了Object中的finalize,equals, toString,hashCode,clone方法,这里仅留下getName()方法):

public class UserServiceB$$EnhancerByCGLIB$$a33459ad extends UserServiceB implements Factory {
    //cglib基于继承,可以看到代理类继承了目标类,并实现了Factory接口,Factory接口可以简化回调函数的变更
    private boolean CGLIB$BOUND;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;//回调函数
    private static final Method CGLIB$getName$0$Method;//目标类的getName方法
    private static final MethodProxy CGLIB$getName$0$Proxy;//getName方法的代理方法
    //初始化变量
    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        //代理类
        Class class_ = Class.forName("cn.john.test.dynamicProxy.UserServiceB$$EnhancerByCGLIB$$a33459ad");
        //目标类
        Class class_2 = Class.forName("cn.john.test.dynamicProxy.UserServiceB");
        Method[] arrmethod = ReflectUtils.findMethods(
                (String[]) new String[]{"getName", "(I)Ljava/lang/String;", "getAge", "(I)Ljava/lang/Integer;"},
                (Method[]) class_2.getDeclaredMethods());
        //getName方法
        CGLIB$getName$0$Method = arrmethod[0];
        //建立更快的方法索引访问方式,这里通过目标类和代理类的Class对象和方法签名为这两个对象
        //的所有方法都建立了索引,并提供了通过索引调用的方法。
        //这里CGLIB$getName$0$Proxy提供在目标类(或者兼容类)上快速调用getName和在代理类上
        //快速调用CGLIB$getName$0的功能
        CGLIB$getName$0$Proxy = MethodProxy.create(class_2, class_, (String) "(I)Ljava/lang/String;",
                (String) "getName", (String) "CGLIB$getName$0");
    }

    //直接调用了目标类的方法,这个方法即用来执行目标类真实逻辑,通过索引调用来快速访问该方法
    final String CGLIB$getName$0(int n) {
        return super.getName(n);
    }

    //代理方法getName入口
    public final String getName(int n) {
    //先获取回调函数
        MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
        if (methodInterceptor == null) {
            UserServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BIND_CALLBACKS((Object) this);
            methodInterceptor = this.CGLIB$CALLBACK_0;
        }
        //获取了回调函数之后
        if (methodInterceptor != null) {
        //调用回调函数的拦截方法。
        //注意这里传入的参数,代理类传入的this,被拦截的方法传入的是目标类对象的
        //被拦截的方法,methodProxy传入的是getName方法的快速访问代理
            return (String) methodInterceptor.intercept((Object) this, CGLIB$getName$0$Method,
                    new Object[]{new Integer(n)}, CGLIB$getName$0$Proxy);
        }
        return super.getName(n);
    }

    public UserServiceB$$EnhancerByCGLIB$$a33459ad() {
        UserServiceB$$EnhancerByCGLIB$$a33459ad userServiceB$$EnhancerByCGLIB$$a33459ad = this;
        UserServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BIND_CALLBACKS((Object) userServiceB$$EnhancerByCGLIB$$a33459ad);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] arrcallback) {
        CGLIB$THREAD_CALLBACKS.set(arrcallback);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] arrcallback) {
        CGLIB$STATIC_CALLBACKS = arrcallback;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object object) {
        UserServiceB$$EnhancerByCGLIB$$a33459ad userServiceB$$EnhancerByCGLIB$$a33459ad = (UserServiceB$$EnhancerByCGLIB$$a33459ad) ((Object) object);
        if (!userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BOUND) {
            userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$BOUND = true;
            Object t = CGLIB$THREAD_CALLBACKS.get();
            if (t != null || (v13465 = CGLIB$STATIC_CALLBACKS) != null) {
                userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$CALLBACK_0 = (MethodInterceptor) ((Callback[]) t)[0];
            }
        }
    }
    static {
        UserServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$STATICHOOK1();
    }
}

进入回调函数后,跟JDK动态代理InvocationHandler一样,先执行前置增强逻辑,然后将目标类的真实逻辑。注意此处目标类的真实逻辑执行cglib的实现方式与JDK实现方式不同:JDK使用的是反射技术,而cglib则使用了FastClass构建方法索引+继承的方式访问目标类的方法。

建立getName方法和CGLIB$getName0的索引
CGLIB$getName$0$Proxy = MethodProxy.create(class_2, class_, (String) "(I)Ljava/lang/String;",
                (String) "getName", (String) "CGLIB$getName$0");
                //注意这里class_2是目标类,class_是代理类

我们截取MethodProxy类的部分代码:

    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();
            }
        }
    }
//注意在MethodProxy类内部变量命名:这里目标类为1,而代理类变为了2
    public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
    //准备数据阶段,目标类和代理类的Class对象,需要映射的方法签名,这里并不会
    //触发实际上的建立方法索引
        MethodProxy proxy = new MethodProxy();
        proxy.sig1 = new Signature(name1, desc);
        proxy.sig2 = new Signature(name2, desc);
        proxy.createInfo = new CreateInfo(c1, c2);
        return proxy;
    }

实际建立方法索引发生在回调函数中方法调用时(Lazyinit):

//MethodProxy类中的InvokeSuper
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            this.init();//实际的方法索引在此时建立
            FastClassInfo fci = this.fastClassInfo;
            //在代理类FastClass对象上调用索引为i2的方法
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }
//内部类FastClassInfo
private static class FastClassInfo {
        FastClass f1;//目标类fc
        FastClass f2;//代理类fc
        int i1;//目标类getName方法索引
        int i2;//代理类CGLIB$getName$0方法索引

        private FastClassInfo() {
        }
    }

    private void init() {
        if (this.fastClassInfo == null) {
            Object object = this.initLock;
            synchronized (object) {
                if (this.fastClassInfo == null) {
                    CreateInfo ci = this.createInfo;
                    FastClassInfo fci = new FastClassInfo();
                    //这里通过字节码技术生成目标类和代理类的FastClass类的实例
                    //FastClass关键有两类方法:
                    //一类是getIndex方法,通过方法签名获取某方法的索引
                    //一类是invoke方法,通过方法的索引来找到方法并调用
                    fci.f1 = MethodProxy.helper(ci, ci.c1);//生成目标类的FastClass对象
                    fci.f2 = MethodProxy.helper(ci, ci.c2);//生成代理类的FastClass对象
                    //获取目标类和代理类的方法索引
                    fci.i1 = fci.f1.getIndex(this.sig1);
                    fci.i2 = fci.f2.getIndex(this.sig2);
                    this.fastClassInfo = fci;//至此,getName方法的索引建立、获取完毕
                    this.createInfo = null;
                }
            }
        }
    }

回到示例上层代码:methodProxy.invokeSuper(obj, args);这里obj是代理对象,再看invokeSuper:

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            init();//建立和获取索引
            FastClassInfo fci = fastClassInfo;
            //在obj即代理对象上调用索引为i2的方法
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

现在我们反编译代理类的FastClass类看一下,fci.f2.invoke(fci.i2, obj, args);到底意味着什么。
代理类FastClass(部分代码):

public class UserServiceB$$EnhancerByCGLIB$$a33459ad$$FastClassByCGLIB$$9e4fc4c5 extends FastClass {
    public UserServiceB$$EnhancerByCGLIB$$a33459ad$$FastClassByCGLIB$$9e4fc4c5(Class class_) {
        super(class_);
    }

    public int getIndex(Signature signature) {
        String string = signature.toString();
        switch (string.hashCode()) {
            case -2024387448 : {
            //在上面的Init方法中我们已经获取了CGLIB$getName$0的索引,值为18
                if (!string.equals("CGLIB$getName$0(I)Ljava/lang/String;"))
                    break;
                return 18;
            }
            case 206620625 : {
                if (!string.equals("getName(I)Ljava/lang/String;"))
                    break;
                return 3;
            }
        }
        return -1;
    }
//在代理对象上调用索引为18的方法
    public Object invoke(int n, Object object, Object[] arrobject) throws InvocationTargetException {
        UserServiceB$$EnhancerByCGLIB$$a33459ad userServiceB$$EnhancerByCGLIB$$a33459ad = (UserServiceB$$EnhancerByCGLIB$$a33459ad) ((Object) object);
        try {
            switch (n) {
                case 3 : {
                    return userServiceB$$EnhancerByCGLIB$$a33459ad.getName(((Number) arrobject[0]).intValue());
                }
                //在代理对象上调用了CGLIB$getName$0方法,回到代理类源码,它调用super.getName,即目标类的真实逻辑
                case 18 : {
                    return userServiceB$$EnhancerByCGLIB$$a33459ad.CGLIB$getName$0(((Number) arrobject[0]).intValue());
                }
            }
        } catch (Throwable v1) {
            throw new InvocationTargetException(v1);
        }
        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
}

现在我们来回答一下为什么示例代码中不能调用invoke,而是只能调用invokeSuper。invoke代码:

public Object invoke(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            //因为在回调函数中obj传入的代理对象,这里实际上是在代理对象上调用
            //getName方法,将陷入无限递归,直至栈溢出
            return fci.f1.invoke(fci.i1, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (IllegalArgumentException e) {
            if (fastClassInfo.i1 < 0)
                throw new IllegalArgumentException("Protected method: " + sig1);
            throw e;
        }
    }

总结

类型 机制 回调方式 适用场景 效率
JDK动态代理 委托机制,代理类和目标类都实现了同样的接口,InvocationHandler持有目标类,代理类委托InvocationHandler去调用目标类的原始方法 反射 目标类是接口类 效率瓶颈在反射调用稍慢
CGLIB动态代理 继承机制,代理类继承了目标类并重写了目标方法,通过回调函数MethodInterceptor调用父类方法执行原始逻辑 通过FastClass方法索引调用 非接口类,非final类,非final方法 第一次调用因为要生成多个Class对象较JDK方式慢,多次调用因为有方法索引较反射方式快,如果方法过多switch case过多其效率还需测试

http://ifeve.com/jdk%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%BB%A3%E7%90%86%E4%B8%8Ecglib%E4%BB%A3%E7%90%86%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/
https://www.jianshu.com/p/9a61af393e41?from=timeline&isappinstalled=0
https://www.jianshu.com/p/13aa63e1ac95
https://www.cnblogs.com/cruze/p/3865180.html
spring技术内幕

猜你喜欢

转载自blog.csdn.net/john_lw/article/details/79539070