当前位置:   article > 正文

理解Java动态代理_surf vp n

surf vp n

概念理解

动态代理类就是在运行时创建的实现了一系列特定接口的类。

为了更好行文,还需要先明确三个概念:

  1. 代理类——在本文中指动态代理类
  2. 代理接口——在本文中指动态代理类实现的接口
  3. 代理实例——在本文中指动态代理类的一个实例

动态代理的一些特性:

  1. 代理类是publicfinal的,不能是abstract
  2. 代理类均继承自java.lang.reflect.Proxy
  3. 代理类在创建时按顺序实现了所指定的接口
  4. 代理类的名称前缀为$Proxy
  5. 代理类有一个public构造函数,参数为实现了InvocationHandler的对象
  6. 每个代理实例都有一个指定的调用处理器InvocationHandlerInvocationHandler作为其构造函数的参数传入
  7. 代理实例的方法调用会触发InvocationHandler接口的invoke方法

源码简析

Proxy类概览

Proxy类位于java.lang.reflect包中,本文以Android SDK中的Proxy类来分析,与Java SDK中的Proxy可能稍有不同。

Proxy提供了一些静态方法用来生成动态代理类及其实例,同时Proxy类是这些动态代理类的父类。

Proxy的主要变量如下,具体请看注释说明:

/** 代理类名称前缀 */
private final static String proxyClassNamePrefix = "$Proxy";

/** 代理类构造函数的参数类型*/
private final static Class[] constructorParams =
    { InvocationHandler.class };

/** 类加载器与对应的代理类缓存映射 */
private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
    = new WeakHashMap<>();

/** 标记某个特定的代理类正在生成 */
private static Object pendingGenerationMarker = new Object();

/** next number to use for generation of unique proxy class names */
private static long nextUniqueNumber = 0;
private static Object nextUniqueNumberLock = new Object();

/** 所有代理类的存储集合,在isProxyClass方法中会用到 */
private static Map<Class<?>, Void> proxyClasses =
    Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>());

/**
 * 代理类实例的调用处理器
 * @serial
 */
protected InvocationHandler h;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

检查某个特定类是否为动态代理类:

public static boolean isProxyClass(Class<?> cl) {
    if (cl == null) {
        throw new NullPointerException();
    }

    return proxyClasses.containsKey(cl);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

可以看到用到了上面定义的proxyClasses

获取代理实例的调用处理器:

public static InvocationHandler getInvocationHandler(Object proxy)
    throws IllegalArgumentException
{
    /*
     * Verify that the object is actually a proxy instance.
     */
    if (!(proxy instanceof Proxy)) {
        throw new IllegalArgumentException("not a proxy instance");
    }
    return ((Proxy) proxy).h;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Proxy类本身还有一个invoke方法:

private static Object invoke(Proxy proxy, Method method, Object[] args) throws Throwable {
    InvocationHandler h = proxy.h;
    return h.invoke(proxy, method, args);
}
  • 1
  • 2
  • 3
  • 4

其他Proxy提供的方法在“动态代理的使用流程分析”一节细说。

InvocationHandler接口

接下来看一下上面多次提到的InvocationHandler接口

/**
 * {@code InvocationHandler} is the interface implemented by
 * the <i>invocation handler</i> of a proxy instance.
 *
 * <p>Each proxy instance has an associated invocation handler.
 * When a method is invoked on a proxy instance, the method
 * invocation is encoded and dispatched to the {@code invoke}
 * method of its invocation handler.
 */
public interface InvocationHandler {

    /**
     * Processes a method invocation on a proxy instance and returns
     * the result.  This method will be invoked on an invocation handler
     * when a method is invoked on a proxy instance that it is
     * associated with.
     */ 
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

注释写的非常清楚,每个代理实例都有一个InvocationHandler对象,实例方法调用时会触发该接口的invoke方法,并返回结果。invoke方法的三个参数分别为代理实例、方法实例(此处的方法实质是代理接口中所定义的方法)、方法参数。

通常我们会自定义一个类实现InvocationHandler接口,如上文示例中的MyInvocationHandler

动态代理的使用流程分析

官方文档给出的生成动态代理类的示例:

// 1.为Foo接口生成动态代理类的步骤
InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class });
Foo f = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { handler });

// 2.更简单的一种调用方式,实际上是对上面几步的整合
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

根据上述两种使用方式,我们来跟踪一下源码。

先看getProxyClass

public static Class<?> getProxyClass(ClassLoader loader,
                                     Class<?>... interfaces)
    throws IllegalArgumentException
{
    return getProxyClass0(loader, interfaces);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

此方法获取一个代理类,参数传入一个类加载器和一个接口数组,最终调到getProxyClass0(ClassLoader loader, Class<?>... interfaces),稍后再来看这个方法的具体实现。

上面得到代理类之后通过getConstructor得到其构造方法,上面说过代理类有一个public构造函数,参数为实现了InvocationHandler的对象,得到构造函数后,然后调用newInstance得到一个代理实例,并将其转为对应的接口对象。

再看第2种简单的实现方式,Proxy.newProxyInstance的实现:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    // 先检验调用处理器
    if (h == null) {
        throw new NullPointerException();
    }

    /*
     * 获取代理类,也是通过调用getProxyClass0
     */
    Class<?> cl = getProxyClass0(loader, interfaces);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        // 获取构造函数
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        return newInstance(cons, h);
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

newInstance(cons, h)的实现为:

private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
    try {
        // 最终还是走Constructor的newInstance方法
        return cons.newInstance(new Object[] {h} );
    } catch (IllegalAccessException | InstantiationException e) {
        throw new InternalError(e.toString());
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString());
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

上面两种方式本质都是一样的,只不过第2种方式对用户使用来说更加简单。

上述两种方式的流程很清楚,接下来看最关键的地方,即动态代理类的生成过程,主要是getProxyClass0的实现,其源码较长,具体看注释吧,如下:

private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    // 校验接口数组的长度
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }

    Class<?> proxyClass = null;

    /* collect interface names to use as key for proxy class cache */
    // 用于存储代理类实现的所有接口的名称
    String[] interfaceNames = new String[interfaces.length];

    // for detecting duplicates
    // 存储不重复的接口类对象
    Set<Class<?>> interfaceSet = new HashSet<>();

    // 循环遍历所有接口
    for (int i = 0; i < interfaces.length; i++) {
        /*
         * Verify that the class loader resolves the name of this
         * interface to the same Class object.
         */
        // 接口名
        String interfaceName = interfaces[i].getName();
        Class<?> interfaceClass = null;
        try {
            // 通过接口名及类加载器得到一个接口类对象
            interfaceClass = Class.forName(interfaceName, false, loader);
        } catch (ClassNotFoundException e) {
        }
        // 校验
        if (interfaceClass != interfaces[i]) {
            throw new IllegalArgumentException(
                interfaces[i] + " 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.contains(interfaceClass)) {
            throw new IllegalArgumentException(
                "repeated interface: " + interfaceClass.getName());
        }
        interfaceSet.add(interfaceClass);

        // 存储接口名称到数组
        interfaceNames[i] = interfaceName;
    }

    /*
     * Using string representations of the proxy interfaces as
     * keys in the proxy class cache (instead of their Class
     * objects) is sufficient because we require the proxy
     * interfaces to be resolvable by name through the supplied
     * class loader, and it has the advantage that using a string
     * representation of a class makes for an implicit weak
     * reference to the class.
     */
    // 上面已经有英文注释了,简单解释一下:使用字符串作(代理接口的名称)作为代理类缓存的key是足够的,因为我们使用类加载器加载时也是使用名称,使用字符串的另一个优势是它对类是隐式的弱引用。
    List<String> key = Arrays.asList(interfaceNames);

    /*
     * Find or create the proxy class cache for the class loader.
     */
    // 为类加载器查找或创建代理类缓存
    Map<List<String>, Object> cache;
    synchronized (loaderToCache) {
        cache = loaderToCache.get(loader);
        if (cache == null) {
            cache = new HashMap<>();
            loaderToCache.put(loader, cache);
        }
        /*
         * This mapping will remain valid for the duration of this
         * method, without further synchronization, because the mapping
         * will only be removed if the class loader becomes unreachable.
         */
    }

    /*
     * Look up the list of interfaces in the proxy class cache using
     * the key.  This lookup will result in one of three possible
     * kinds of values:
     *     null, if there is currently no proxy class for the list of
     *         interfaces in the class loader,
     *     the pendingGenerationMarker object, if a proxy class for the
     *         list of interfaces is currently being generated,
     *     or a weak reference to a Class object, if a proxy class for
     *         the list of interfaces has already been generated.
     */
    // 3种查找结果:(1)null(2)pendingGenerationMarker对象(3)一个类对象的弱引用
    synchronized (cache) {
        /*
         * Note that we need not worry about reaping the cache for
         * entries with cleared weak references because if a proxy class
         * has been garbage collected, its class loader will have been
         * garbage collected as well, so the entire cache will be reaped
         * from the loaderToCache map.
         */
        // 如果一个代理类被GC了,它对应的类加载器也会被GC
        do {
            Object value = cache.get(key);
            // 结果1:返回弱引用,从中得到代理类
            if (value instanceof Reference) {
                proxyClass = (Class<?>) ((Reference) value).get();
            }
            if (proxyClass != null) {
                // proxy class already generated: return it
                // 代理类已经生成,并返回
                return proxyClass;
            } else if (value == pendingGenerationMarker) {
                // 结果2:返回pendingGenerationMarker,表示代理类正在生成
                // proxy class being generated: wait for it
                try {
                    cache.wait();
                } catch (InterruptedException e) {
                    /*
                     * The class generation that we are waiting for should
                     * take a small, bounded time, so we can safely ignore
                     * thread interrupts here.
                     */
                }
                continue;
            } else {
                // 结果3:返回null,表示目前还没生成代理类,先在缓存中存储一个标记
                /*
                 * No proxy class for this list of interfaces has been
                 * generated or is being generated, so we will go and
                 * generate it now.  Mark it as pending generation.
                 */
                cache.put(key, pendingGenerationMarker);
                break;
            }
        } while (true);
    }

    try {
        // 代理类的包名
        String proxyPkg = null;     // package to define proxy class in

        /*
         * 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 (int i = 0; i < interfaces.length; i++) {
            int flags = interfaces[i].getModifiers();
            if (!Modifier.isPublic(flags)) {
                String name = interfaces[i].getName();
                int n = name.lastIndexOf('.');
                // 举个列子,如果name=com.abc.Testinterface,则pkg=com.abc.
                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.
            // 默认包名为com.sun.proxy
            proxyPkg = "";
        }

        {
            // Android-changed: Generate the proxy directly instead of calling
            // through to ProxyGenerator.
            // 请注意上面注释,Android中有变动,直接调用Native方法生成代理类而不是通过ProxyGenerator
            // 下面方法通过递归获取接口中的所有方法
            List<Method> methods = getMethods(interfaces);
            // 根据前面及类型排序
            Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
            // 对方法返回类型进行校验,Throws if any two methods in {@code methods} have the same name and parameters but incompatible return types.
            validateReturnTypes(methods);
            // Remove methods that have the same name, parameters and return type. This computes the exceptions of each method; this is the intersection of the exceptions of equivalent 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.
             */
            final long num;
            synchronized (nextUniqueNumberLock) {
                num = nextUniqueNumber++;
            }
            // 生成的动态代理类名,如com.sun.proxy.$Proxy0,com.sun.proxy.$Proxy1,com.sun.proxy.$Proxy2
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            // generateProxy为Native方法
            proxyClass = generateProxy(proxyName, interfaces, loader, methodsArray,
                    exceptionsArray);
        }
        // add to set of all generated proxy classes, for isProxyClass
        proxyClasses.put(proxyClass, null);

    } finally {
        /*
         * We must clean up the "pending generation" state of the proxy
         * class cache entry somehow.  If a proxy class was successfully
         * generated, store it in the cache (with a weak reference);
         * otherwise, remove the reserved entry.  In all cases, notify
         * all waiters on reserved entries in this cache.
         */
        // 代理类生成之后,清除之前Cache中的标记状态,并将其以弱引用的方式保存
        synchronized (cache) {
            if (proxyClass != null) {
                cache.put(key, new WeakReference<Class<?>>(proxyClass));
            } else {
                cache.remove(key);
            }
            // 唤醒前面cache.wait()
            cache.notifyAll();
        }
    }
    // 返回动态代理类
    return proxyClass;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236

动态代理示例

示例1

先定义一个代理接口,描述如何”上网冲浪“:

package com.aspook.dynamicproxy2;

public interface SurfInternet {
    void surf(String content);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

再定义一个委托类:

public class Normal implements SurfInternet {
    @Override
    public void surf(String content) {
        System.out.println("上网: " + content);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

创建一个自定义的InvocationHandler

public class VPNInvocationHandler implements InvocationHandler {

    private SurfInternet base;

    public VPNInvocationHandler(SurfInternet obj) {
        base = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoke start");

        // 会调用委托类的对应方法,从而实现代理
        method.invoke(base, args);

        System.out.println("invoke end");
        return null;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

测试类:

public class Test {
    public static void main(String[] args) {
        // 被代理类,或叫做委托类
        Normal normal = new Normal();
        InvocationHandler h = new VPNInvocationHandler(normal);
        SurfInternet vpn = (SurfInternet) Proxy.newProxyInstance(normal.getClass().getClassLoader(),
                normal.getClass().getInterfaces(),
                h);

        vpn.surf("VPN方式,可以访问Google了");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

输出结果:

invoke start
上网: VPN方式,可以访问Google了
invoke end

注意第2行的输出,实质上是被代理类的功能,代理类一般用于不想将被代理类暴露出去,而是转用代理类来实现被代理类的功能,即所谓的代理。在上面的例子有一个被代理类Normal,与静态代理模式相比(本质上是代理类持有一个被代理类的实例,代理类与被代理类均实现相同接口),动态代理在运行时才会生成。

示例2

先定义一个代理接口:

package com.aspook.dynamicproxy;

public interface HelloService {
    void sayHello(String content);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意此接口为public,位于com.aspook.dynamicproxy包下,按上文分析,生成的动态代理类应该位于默认包中,包名为com.sun.proxy,稍后验证。

再来实现一个逻辑类ProxyClassTest,具体请看注释:

public class ProxyClassTest {
    private InvocationHandler h;

    // 初始化一个InvocationHandler
    public void prepareInvocationHandler() {
        h = new MyInvocationHandler();
    }

    // 只有一个代理接口示例
    public <T> T create(Class<T> service) {
        return (T) Proxy.newProxyInstance(service.getClassLoader(),
                new Class[]{service}, h);
    }

    // 这里有两个代理接口,GoodService代表另一个接口,源码未给出
    public <T> T create() {
        return (T) Proxy.newProxyInstance(HelloService.class.getClassLoader(),
                new Class[]{HelloService.class, GoodService.class}, h);
    }

    // 代理实例方法调用触发invoke回调后可执行的个人逻辑
    private void doLogic(String firstArg) {
        System.out.println(firstArg);
    }

    // InvocationHandler的实现类,当然也可以用匿名内部类
    class MyInvocationHandler implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("invoke");
            System.out.println("proxy: " + proxy.getClass());
            System.out.println("method: " + method.getName());
            System.out.println("args length: " + args.length);
            // 由于只是示例,仅供说明,因此下面两行未做越界校验
            System.out.println("args : " + args[0].toString());
            doLogic(args[0].toString());

            // 注意返回值要跟接口方法返回值相对应
            return null;
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

最后看下调用类:

public class Test {
    public static void main(String[] args) {
        ProxyClassTest test = new ProxyClassTest();
        test.prepareInvocationHandler();
        HelloService service = test.create();
        service.sayHello("hahaha");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

最终输入结果如下:

invoke
proxy: class com.sun.proxy.$Proxy0
method: sayHello
args length: 1
args : hahaha
custom logic: hahaha

由输出结果可以看到代理全路径名称为com.sun.proxy.$Proxy0,跟前文中的理论一致,同时可以得到方法名和方法参数,并可执行自定义逻辑。

此示例并没有实现被代理类,多个接口的响应均统一在invoke中处理,然后实现具体逻辑,而不必像静态代理那样单独实现每一个接口。Retrofit也是利用了此原理。

注意事项

  1. 如果代理接口有多个,如下面代码有HelloServiceGoodService两个接口

    public <T> T create() {
       return (T) Proxy.newProxyInstance(HelloService.class.getClassLoader(),
               new Class[]{HelloService.class, GoodService.class}, h);
    }
    • 1
    • 2
    • 3
    • 4

    只要有一个接口为非public的,则生成的动态代理类就跟接口同包,如com.aspook.dynamicproxy.$Proxy0

  2. 如果多个接口返回类型不同,可以在invoke中根据方法的返回类型来return不同的值。

  3. 如果跨包引用一个代理接口,则该接口必然为public的,如果只有这一个接口则动态代理类位于默认包中;如果还有其他同包的代理接口,只要有一个为非public的,则生成的动态代理类就跟非public的接口同包,如果无论跨包同包所有接口均为public,则生成的动态代理类在默认包中。

  4. 由于动态代理类本身已经继承了Proxy,根据Java单继承的限制,因此只能实现多个接口了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/98521
推荐阅读
相关标签
  

闽ICP备14008679号