zoukankan      html  css  js  c++  java
  • 动态代理三部曲(一):动态代理模式及实现原理

    一、背景

    代理模式,作为常用的设计模式之一,在实际项目中或多或少都会被使用到。当前一些主流的项目框架中,也有不少代理模式的身影。

    代理模式中,代理类与主体类实现同样的接口,代理类持有实体类的引用,并接受客户端对代理类中实体引用的外部注入,并代理实体类的功能。
    注:描述中的这种外部注入形式有个专有技术名词:依赖注入

    代理模式通用的类图为:

    按照代理类的产生方式,是在运行期之前就静态的存在还是在运行期动态产生,可以将代理模式分为静态代理和动态代理。


    二、静态代理

    在真正理解动态代理之前,有必要先简单回顾下静态代理的一般过程。

    直接看一个具体的实例。
    1,定义接口:

    package com.corn.proxy.pstatic;
    
    public interface Subject {
    
        String action();
    
    }
    复制代码

    2,定义主体类:

    package com.corn.proxy.pstatic;
    
    public class RealSubject implements Subject {
    
        @Override
        public String action() {
            System.out.println("action in RealSubject");
            return "action done";
        }
    }
    复制代码

    3,定义静态代理类:

    package com.corn.proxy.pstatic;
    
    public class ProxySubject implements Subject{
    
        private Subject realSubject;
    
        public ProxySubject(Subject realSubject) {
            this.realSubject = realSubject;
        }
    
        @Override
        public String action() {
            // 主体action前执行
            System.out.println("do sth before RealSubject action");
            String result = this.realSubject.action();
            // 主体action后执行
            System.out.println("do sth after RealSubject action");
    
            return result;
        }
    }
    复制代码

    4,客户端注入实体并访问:

    package com.corn.proxy.pstatic;
    
    
    public class Client {
    
        public static void main(String[] args) {
            Subject realSubject = new RealSubject();
            ProxySubject proxySubject = new ProxySubject(realSubject);
    
            proxySubject.action();
        }
    }
    复制代码

    run,输出结果:

    do sth before RealSubject action
    action in RealSubject
    do sth after RealSubject action
    复制代码

    上述代码过程亦对应了代理模式类图结构。


    三、动态代理

    本质上,动态代理也是遵循上述通用的代理模式类图关系,与静态代理相比,其动态主要体现在: 1,具体代理类(ProxySubject)的生成是在运行期动态产生的,而非编译期就已经静态存在;
    2,具体代理类(ProxySubject)与被代理类的代理关系(ProxySubject持有RealSubject的引用),是想办法动态注入进入的;
    3,具体代理类(ProxySubject)对被代理类的功能的代理是在动态生成的代理类内部,想办法去动态的调用被代理类的对应方法的。

    无论是具体代理类的动态产生,还是与被代理类的关系建立,以及对被代理类方法的代理调用,这中间,都用到了两个关键的中间媒介,即Proxy和InvocationHandler。

    Proxy类,其中提供了动态生成代理类的静态方法,并持有实现了InvocationHandler接口的引用。同时,所有生成的代理类也都是Proxy类的子类。

    InvocationHandler接口,只包含一个抽象出来的方法名:invoke,使得实现InvocationHandler接口的类去具体实现,在实现中通过持有被代理类实体(RealSubject),并通过反射,去调用对应的实体方法。

    因此,动态代理总体上的执行流程为:
    当客户端通过Proxy的静态方法生成动态代理类后,调用动态代理类对应的接口方法时,内部会调用其内部持有的InvocationHandler接口的实例对象的invoke方法,并得以调用到实际被代理实体的相应方法。

    将总体的类之间关系如果用类图表示,与通用的代理模式类图稍有区别。

    相应代码实现代码过程如下:
    1,定义接口Subject:

    package com.corn.proxy.pdynamic;
    
    public interface Subject {
    
        String action();
    
    }
    复制代码

    2,定义主体类:

    package com.corn.proxy.pdynamic;
    
    public class RealSubject implements Subject{
    
        @Override
        public String action() {
            System.out.println("action in RealSubject");
            return "action done";
        }
    }
    复制代码

    3,定义实现了InvocationHandler接口的类:

    package com.corn.proxy.pdynamic;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class ProxyInvocationHandler implements InvocationHandler {
    
        protected Subject subject;
    
        public ProxyInvocationHandler(Subject subject) {
            this.subject = subject;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("do something before in ProxyInvocationHandler");
            return method.invoke(subject, args);
        }
    
    }
    复制代码

    4,客户端注入实体并访问:

    package com.corn.proxy.pdynamic;
    
    import java.lang.reflect.Proxy;
    
    public class Client {
    
        public static void main(String[] args) {
            Subject realSubject = new RealSubject();
            ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(realSubject);
    
            Subject proxyRealSubject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),
                    realSubject.getClass().getInterfaces(), proxyInvocationHandler);
    
            proxyRealSubject.action();
        }
    }
    复制代码

    run,输出结果:

    do something before in ProxyInvocationHandler
    action in RealSubject
    复制代码

    四、实现原理

    从上述动态代理执行流程和类图分析中已经可以看出,动态代理的关键,在于通过InvocationHandler和Proxy媒介,在运行时动态生成动态代理类,生成的动态代理类依然实现了Subject接口,并在调用方法时回调了InvocationHandler实现类的invoke方法,InvocationHandler实现类的invoke方法通过反射,回调了被代理实体的对应方法。

    看起来有点绕。

    在生成动态代理过程中,Java工程和Android项目中有点区别,先从源码角度看下Java工程的具体实现过程。

    Android studio中不能直接新建Java工程,但可以在Android项目中通过建立Java Library的方式,建立Java库。默认情况下,Android Studio关联的JDK为AS内置的,是看不到源码的,为此,需要将其改成自己下载的JDK路径,此路中包含了源码src目录。 具体修改方式为:
    1,查看本地JDK目录

    /usr/libexec/java_home -V
    复制代码

    输出

    Matching Java Virtual Machines (1):
        1.8.0_162, x86_64:	"Java SE 8"	/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home
    
    /Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home
    复制代码

    2,Android Studio替换JDK设置 File >> Other Setting >> Default Project Structure,在JDK Location中将默认设置

    /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home
    复制代码

    修改为:

    /Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home
    复制代码

    完成设置后,可以直接看到JDK源码。

    ProxyInvocationHandler接口只有一个方法:

    public interface InvocationHandler {
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    }
    复制代码

    下面重点看下Proxy类newProxyInstance过程。

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
    {
        Objects.requireNonNull(h);
    
        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<?> cl = getProxyClass0(loader, intfs);
    
        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
    
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }
    复制代码

    其中调用的getProxyClass0对应的具体实现为:

    /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
    
        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }
    复制代码

    于是,我们跟到对应的ProxyClassFactory:

    /**
     * A factory function that generates, defines and returns the proxy class given
     * the ClassLoader and array of interfaces.
     */
    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();
    
        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }
    
            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
    
            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }
    
            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }
    
            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }
    复制代码

    其中,关键的过程在于:

    /*
     * Generate the specified proxy class.
     */
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
        proxyName, interfaces, accessFlags);
    try {
        return defineClass0(loader, proxyName,
                            proxyClassFile, 0, proxyClassFile.length);
    } catch (ClassFormatError e) {
       ...
    }
    复制代码

    通过ProxyGenerator类中的generateProxyClass方法生成对应的动态代理类二进制代码,并通过 ClassLoader加载后,通过反射,生成对应的类实例。

    ProxyGenerator类是直接集成在rt.jar中的,包名为sun.misc,为扩展类。Android项目中因JDK版本问题,默认是不集成的,那Android中此处是如何实现的呢?

    同样的,在Android项目中直接使用动态代理,跟踪源码调用过程。

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
    {
        Objects.requireNonNull(h);
    
        final Class<?>[] intfs = interfaces.clone();
        // Android-removed: SecurityManager calls
        /*
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
        */
    
        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);
    
        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            // Android-removed: SecurityManager / permission checks.
            /*
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            */
    
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                // BEGIN Android-changed: Excluded AccessController.doPrivileged call.
                /*
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
                */
    
                cons.setAccessible(true);
                // END Android-removed: Excluded AccessController.doPrivileged call.
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }
    复制代码

    很明显,Android JDK中newProxyInstance方法中部分实现做了修改。但主要执行路径依然不变。

    /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
    
        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }
    复制代码

    同样的,ProxyClassFactory类。

    /**
     * A factory function that generates, defines and returns the proxy class given
     * the ClassLoader and array of interfaces.
     */
    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();
    
        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }
    
            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
    
            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }
    
            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use the default package.
                proxyPkg = "";
            }
    
            {
                // Android-changed: Generate the proxy directly instead of calling
                // through to ProxyGenerator.
                List<Method> methods = getMethods(interfaces);
                Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
                validateReturnTypes(methods);
                List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);
    
                Method[] methodsArray = methods.toArray(new Method[methods.size()]);
                Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);
    
                /*
                 * Choose a name for the proxy class to generate.
                 */
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                return generateProxy(proxyName, interfaces, loader, methodsArray,
                                     exceptionsArray);
            }
        }
    }
    复制代码

    其中关键的,我们发现

    // Android-changed: Generate the proxy directly instead of calling
    // through to ProxyGenerator.
    ...
    return generateProxy(proxyName, interfaces, loader, methodsArray,
                         exceptionsArray);
    复制代码

    跟踪进去看下具体的执行过程

    @FastNative
    private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
                                                 ClassLoader loader, Method[] methods,
                                                 Class<?>[][] exceptions);
    // END Android-changed: How proxies are generated.
    复制代码

    原来,Android JDK中对generateProxy进行了处理,直接使用的是本地的方法。

    那么,生成动态代理时,如果遇到线程安全问题呢?
    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();
        
        ...
        
        /*
         * Choose a name for the proxy class to generate.
         */
        long num = nextUniqueNumber.getAndIncrement();
        String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
        /*
         * Generate the specified proxy class.
         */
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
            proxyName, interfaces, accessFlags);
        try {
            return defineClass0(loader, proxyName,
                                proxyClassFile, 0, proxyClassFile.length);
        } catch (ClassFormatError e) {
            ...
        }
    }
    复制代码

    显然,通过线程安全的文件命名方式,预防了针对同样的接口使用多线程情况下,使用动态代理可能出现的线程安全问题。

    那么,生成的动态代理到底长什么样子?我们可以直接调用系统的ProxyGenerator.generateProxyClass试一下。

    package com.corn.proxy.pdynamic;
    
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.lang.reflect.Proxy;
    
    import sun.misc.ProxyGenerator;
    
    public class Client {
    
        public static void main(String[] args) {
            Subject realSubject = new RealSubject();
            ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(realSubject);
    
            Subject proxyRealSubject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),
                    realSubject.getClass().getInterfaces(), proxyInvocationHandler);
    
            proxyRealSubject.action();
    
            String proxyName = "ProxySubject";
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, RealSubject.class.getInterfaces());
    
            try (FileOutputStream fos = new FileOutputStream("/Users/corn/T/ProxySubject.class")){
                fos.write(proxyClassFile);
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    复制代码

    run,对应目录下生成ProxySubject.class文件,通过工具可以看到对应的字节码内容。

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    import com.corn.proxy.pdynamic.Subject;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class ProxySubject extends Proxy implements Subject {
        private static Method m1;
        private static Method m2;
        private static Method m0;
        private static Method m3;
    
        public ProxySubject(InvocationHandler var1) throws  {
            super(var1);
        }
    
        public final boolean equals(Object var1) throws  {
            try {
                return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        public final String toString() throws  {
            try {
                return (String)super.h.invoke(this, m2, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final int hashCode() throws  {
            try {
                return (Integer)super.h.invoke(this, m0, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        public final String action() throws  {
            try {
                return (String)super.h.invoke(this, m3, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
                m3 = Class.forName("com.corn.proxy.pdynamic.Subject").getMethod("action");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
    复制代码

    果然,在生成的动态代理中,实现了Subject接口,并在对应的action方法中,调用了InvocationHandler实现类的实例的invoke方法。


    五、结语

    动态代理作为代理模式中的一种,避免了在运行期之前直接定义静态代理类,对于需要大量的代理类的情形下,是非常有用的。同时,我们也应该看到,在整体流程上,其实动态代理与静态代理总体上还是一样的。动态代理无论在代理类的创建过程中,还是对代理方法的调用,过程中都用到了反射,在一定程度上性能上有所损耗,实际使用中需要适量权衡。

    动态代理模式,作为设计模式中相对比较难理解的一种,主要在于其过程经过了层层封装,最后只是通过Proxy类和InvocationHandler对外直接暴露了使用接口,对使用方直接屏蔽了具体的细节。但对于我们理解这种模式本身来说,了解并适当掌握其中的过程,还是有所受益的。


    作者:HappyCorn
    链接:https://juejin.im/post/5d047101f265da1bb2772e09
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    webpack高级概念,Dllplugin打包性能配置(系列十八)
    webpack高级概念,resolve配置(配置文件格式以及文件路径变量)(系列十七)
    webpack高级概念,eslint配置(系列十六)
    webpack高级概念,解决单页面应用路由问题(vue用脚手架,404找不到页面二)(系列十五)
    webpack高级概念,webpack-dev-server解决单页面应用路由问题(手动搭建webpack,不是用脚手架,404找不到页面,一)(系列十五)
    webpack高级概念,使用 WebpackDevServer 实现请求转发二(系列十四)
    webpack高级概念,使用 WebpackDevServer 实现请求转发一 (系列十四)
    webpack高级概念,typeScript的打包配置(系列十三)
    DevEco Device Tool 2.1 Beta1 的Hi3861在Windows平台的编译体验
    最全HarmonyOS文档和社区资源使用技巧
  • 原文地址:https://www.cnblogs.com/lwbqqyumidi/p/11991730.html
Copyright © 2011-2022 走看看