JAVA动态代理

代理模式

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

静态代理

代理类HelloProxy

public class HelloProxy implements HelloInterface{
    private HelloInterface helloInterface = new Hello();
    @Override
    public void sayHello() {
        System.out.println("Before invoke sayHello" );
        helloInterface.sayHello();
        System.out.println("After invoke sayHello");
    }
}

接口HelloInterface

public interface HelloInterface {
    void sayHello();
}

继承接口的方法Hello

public class Hello implements HelloInterface{
    @Override
    public void sayHello() {
        System.out.println("Hello Zero!");
    }
}

主函数

public class Main {
    public static void main(String[] args) {
        HelloProxy helloProxy = new HelloProxy();
        helloProxy.sayHello();
    }
}

运行结果

Before invoke sayHello
Hello Zero!
After invoke sayHello

使用静态代理完成了对一个类的代理操作。但是静态代理也有缺点:由于代理只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。

动态代理

利用反射机制在运行时创建代理类。

接口和继承接口的方法不变。

代理类ProxyHandler

创建代理类,继承自InvocationHandler,InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。

每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用。

public class ProxyHandler implements InvocationHandler {
    private Object object;

    public ProxyHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoke " + method.getName());
        method.invoke(object, args);
        System.out.println("After invoke " + method.getName());
        return null;
    }
}

主函数

public class Main {
    public static void main(String[] args) {
        //将JDK动态代理生成的class文件保存到本地
        System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        HelloInterface hello = new Hello();

        InvocationHandler handler = new ProxyHandler(hello);

        HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);

        proxyHello.sayHello();

    }
}

运行结果

Before invoke sayHello
Hello Zero!
After invoke sayHello

我们可以看到方法正常执行了,主函数中通过Proxy类的静态方法newProxyInstance返回一个接口的代理实例,针对不同的代理类,传入相应的代理程序控制器InvocationHandler,就可以返回相应的代理实例。

比如:新建几个方法

public class Cat implements CatInterface {
    @Override
    public void say() {
        System.out.println("I'm Cat");
    }
}
public interface CatInterface {
    void say();
}
public class Mouse implements MouseInterface {
    @Override
    public void say() {
        System.out.println("I'm mouse");
    }
}
public interface MouseInterface {
    void say();
}

再执行主函数

public class Main {
    public static void main(String[] args) {
        //将JDK动态代理生成的class文件保存到本地
        System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        HelloInterface hello = new Hello();

        InvocationHandler handler = new ProxyHandler(hello);

        HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);

        proxyHello.sayHello();

        MouseInterface mouse = new Mouse();
        CatInterface cat = new Cat();

        InvocationHandler handlerMouse = new ProxyHandler(mouse);
        InvocationHandler handlerCat = new ProxyHandler(cat);

        MouseInterface proxyMouse = (MouseInterface) Proxy.newProxyInstance(mouse.getClass().getClassLoader(), mouse.getClass().getInterfaces(), handlerMouse);

        CatInterface proxyCat = (CatInterface) Proxy.newProxyInstance(cat.getClass().getClassLoader(), cat.getClass().getInterfaces(), handlerCat);

        proxyMouse.say();

        proxyCat.say();

    }
}

结果如下,所有方法正常执行

Before invoke sayHello
Hello Zero!
After invoke sayHello
Before invoke say
I'm mouse
After invoke say
Before invoke say
I'm Cat
After invoke say

动态代理的实现

  • 通过实现 InvocationHandler 接口创建自己的调用处理器;
  • 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  • 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  • 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入;

Proxy.newProxyInstance

    package java.lang.reflect;

    public class Proxy implements java.io.Serializable {    

    /**
     * Returns an instance of a proxy class for the specified interfaces    返回指定接口的代理类的实例,该实例将方法调用分派到指定的调用处理程序。
     * that dispatches method invocations to the specified invocation
     * handler.
     *
     * 

{@code Proxy.newProxyInstance} throws * {@code IllegalArgumentException} for the same reasons that * {@code Proxy.getProxyClass} does. * * @param loader the class loader to define the proxy class @param loader类加载器,用于定义代理类 * @param interfaces the list of interfaces for the proxy class @param interfaces代理类要实现的接口列表 * to implement * @param h the invocation handler to dispatch method invocations to @param h调用处理程序,以分派方法调用以使用指定类加载器定义并实现指定接口的代理类的指定调用处理程序来返回代理实例。 * @return a proxy instance with the specified invocation handler of a * proxy class that is defined by the specified class loader * and that implements the specified interfaces * @throws IllegalArgumentException if any of the restrictions on the @throws IllegalArgumentException,如果对可能传递给{@code getProxyClass}的参数被违反 * parameters that may be passed to {@code getProxyClass} * are violated * @throws SecurityException if a security manager, s, is present 如果存在安全管理器 s 并且满足以下任何条件,则@throws SecurityException: * and any of the following conditions is met: *

    *
  • the given {@code loader} is {@code null} and 给定的{@code loader}为{@code null},而调用者的类加载器不是{@code null},并使用{@code RuntimePermission(“ getClassLoader”)调用 * the caller's class loader is not {@code null} and the {@link SecurityManager#checkPermission s.checkPermission} “)}权限拒绝访问; * invocation of {@link SecurityManager#checkPermission * s.checkPermission} with * {@code RuntimePermission("getClassLoader")} permission * denies access;
  • *
  • for each proxy interface, {@code intf}, 对于每个代理接口{@code intf},调用者的类加载器与{@code intf}和调用{@link SecurityManager#checkPackageAccess * the caller's class loader is not the same as or an s.checkPackageAccess()的类加载器都不相同或不相同}拒绝访问{@code intf}; * ancestor of the class loader for {@code intf} and * invocation of {@link SecurityManager#checkPackageAccess * s.checkPackageAccess()} denies access to {@code intf};
  • *
  • any of the given proxy interfaces is non-public and the 任何给定的代理接口都是非公共的,并且调用方类与非公共接口不在同一个{@linkplain软件包运行时软件包}中,并且使用以下命令调用{@link * caller class is not in the same {@linkplain Package runtime package} SecurityManager#checkPermission s.checkPermission} {@code ReflectPermission(“ newProxyInPackage。{package name}”)}权 * as the non-public interface and the invocation of 限拒绝访问。 * {@link SecurityManager#checkPermission s.checkPermission} with * {@code ReflectPermission("newProxyInPackage.{package name}")} * permission denies access.
  • *
* @throws NullPointerException if the {@code interfaces} array * argument or any of its elements are {@code null}, or * if the invocation handler, {@code h}, is * {@code null} */ @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) throws IllegalArgumentException { //判断InvocationHandler是否为空,若为空,抛出空指针异常 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; //如果Class作用域为私有,通过反射 setAccessible 支持访问 if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction() { public Void run() { cons.setAccessible(true); return null; } }); } //获取Proxy Class构造函数,创建Proxy代理实例。 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); } }

Proxy.getProxyClass0

利用getProxyClass0(loader, intfs)生成代理类Proxy的Class对象

    package java.lang.reflect;

    public class Proxy implements java.io.Serializable {
    
    /**
     * a cache of proxy classes    在此初始化WeakCache
     */
    private static final WeakCache[], Class>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    /**
     * Generate a proxy class.  Must call the checkProxyAccess method    生成代理类。 在调用此方法之前,必须调用checkProxyAccess方法执行权限检查。
     * to perform permission checks before calling this.
     */
    private static Class getProxyClass0(ClassLoader loader,
                                           Class... interfaces) {
        if (interfaces.length > 65535) {
            //如果接口数量大于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
        //如果存在由实现了给定接口的给定加载器定义的代理类,则将仅返回缓存的副本;否则,它将通过ProxyClassFactory创建代理类。
        return proxyClassCache.get(loader, interfaces);
    }

WeakCache.get(K key, P parameter)

其中缓存使用WeakCache实现,使用ProxyClassFactory创建代理,ProxyClassFactory是Proxy类的静态内部类,实现了BiFunction接口中的apply方法,当WeakCache中没有缓存相应接口的代理类,则会调用ProxyClassFactory类的apply方法来创建代理类。

   package java.lang.reflect;

   final class WeakCache { 
   /**
     * Look-up the value through the cache. This always evaluates the                通过缓存查找值。如果缓存中没有给定的条目或者实体已经被清除,这总是评估{@code subKeyFactory}函数,并有选择地评估{@code valueFactory}函数
     * {@code subKeyFactory} function and optionally evaluates
     * {@code valueFactory} function if there is no entry in the cache for given
     * pair of (key, subKey) or the entry has already been cleared.
     *
     * @param key       possibly null key                                         @param键可能为空键
     * @param parameter parameter used together with key to create sub-key and        
     *                  value (should not be null)
     * @return the cached value (never null)
     * @throws NullPointerException if {@code parameter} passed in or
     *                              {@code sub-key} calculated by
     *                              {@code subKeyFactory} or {@code value}
     *                              calculated by {@code valueFactory} is null.
     */
    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        // 懒加载 为特定的cacheKey设置第二级valuesMap
        ConcurrentMap> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            //如果valuesMap为null,就新建一个,如果不为null,就取oldValue
            ConcurrentMap> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier stored by that    创建subKey并从valuesMap中检索该subKey存储的可能的Supplier
        // subKey from valuesMap
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        //获取supplier
        Supplier supplier = valuesMap.get(subKey);
        Factory factory = null;
        //自旋,等待supplier不为空
        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue instance
                // 如果缓存中没有,就调用ProxyClassFactory方法创建    此时supplier是WeakCache$Factory,调用WeakCache中Factory的get方法
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // lazily construct a Factory    工厂懒加载,在此初始化并构造factory为WeakCache$Factory
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {
                //从valuesMap中加载
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    // 从valuesMap中还是得不到,就使用factory赋值supplier,赋值后supplier不为null,while自旋将生效
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

WeakCache.Factory

     package java.lang.reflect;    
 
    final class WeakCache {
    /**
     * A factory {@link Supplier} that implements the lazy synchronized    工厂{@link Supplier}实现了值的惰性同步构造并将其安装到缓存中。
     * construction of the value and installment of it into the cache.
     */
    private final class Factory implements Supplier {

        private final K key;
        private final P parameter;
        private final Object subKey;
        private final ConcurrentMap> valuesMap;

        Factory(K key, P parameter, Object subKey,
                ConcurrentMap> valuesMap) {
            this.key = key;
            this.parameter = parameter;
            this.subKey = subKey;
            this.valuesMap = valuesMap;
        }

        @Override
        public synchronized V get() { // serialize access
            // re-check
            Supplier supplier = valuesMap.get(subKey);
            if (supplier != this) {
                // something changed while we were waiting:
                // might be that we were replaced by a CacheValue
                // or were removed because of failure ->
                // return null to signal WeakCache.get() to retry
                // the loop
                return null;
            }
            // else still us (supplier == this)

            // create new value
            V value = null;
            try {
                //调用Proxy类中静态内部类ProxyClassFactory的apply创建代理类    valueFactory此时是Proxy.ProxyClassFactory
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { // remove us on failure
                    valuesMap.remove(subKey, this);
                }
            }
            // the only path to reach here is with non-null value
            assert value != null;

            // wrap value with CacheValue (WeakReference)
            CacheValue cacheValue = new CacheValue<>(value);

            // try replacing us with CacheValue (this should always succeed)
            if (valuesMap.replace(subKey, this, cacheValue)) {
                // put also in reverseMap
                reverseMap.put(cacheValue, Boolean.TRUE);
            } else {
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            return value;
        }
    }

Proxy.ProxyClassFactory

    package java.lang.reflect;

    public class Proxy implements java.io.Serializable {
        

    /**
     * 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[], 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, 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.
                 * 校验该类是否是接口类型    JAVA是单继承的,代理类已经继承了Proxy类了,不能再继承其他的类
                 */
                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
                // public代理接口,使用com.sun.proxy包名
                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 {
                // 使用类加载器将代理类的字节码文件加载到JVM中
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the    这里的ClassFormatError表示(排除代理类生成代码中的错误)提供给代理类创建的参数还有其他一些无效方面(例如,超出了虚拟机限制)
                 * 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());
            }
        }
    }
        
    //用户和本地C代码进行互操作的API,称为Java Native Interface (Java本地接口)
    private static native Class defineClass0(ClassLoader loader, String name,
                                                byte[] b, int off, int len);

ProxyGenerator.generateProxyClass

我们可以看到在ProxyClassFactory类的apply方法中可看出真正生成代理类字节码的地方是ProxyGenerator类中的generateProxyClass

    package sun.misc;

    public class ProxyGenerator 
    
    public static byte[] generateProxyClass(final String var0, Class[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        final byte[] var4 = var3.generateClassFile();
        //是否要将生成代理类的字节码文件保存到磁盘中
        if (saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction() {
                public Void run() {
                    try {
                        int var1 = var0.lastIndexOf(46);
                        Path var2;
                        if (var1 > 0) {
                            Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
                            Files.createDirectories(var3);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class");
                        }

                        Files.write(var2, var4, new OpenOption[0]);
                        return null;
                    } catch (IOException var4x) {
                        throw new InternalError("I/O exception saving generated file: " + var4x);
                    }
                }
            });
        }
        return var4;
    }

代理类

在Main函数中增加,将JDK动态代理生成的class文件保存到本地,保存路径com.sun.proxy

System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

打开生成的代理类

  1. 继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。
  2. 提供了一个使用InvocationHandler作为参数的构造方法。
  3. 生成静态代码块来初始化接口中方法的Method对象,以及Object类的equals、hashCode、toString方法。
  4. 重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法,即可以对其进行特殊的操作,也就是说JDK的动态代理还可以代理上述三个方法。
  5. 代理类实现代理接口的sayHello方法中,只是简单的调用了InvocationHandler的invoke方法,我们可以在invoke方法中进行一些特殊操作,甚至不调用实现的方法,直接返回。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import com.example.offer.designmode.proxy.dynamicproxy.CatInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy2 extends Proxy implements CatInterface {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy2(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 void say() throws  {
        try {
            super.h.invoke(this, m3, (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);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.example.offer.designmode.proxy.dynamicproxy.CatInterface").getMethod("say");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

你可能感兴趣的:(动态代理,java)