News:三分天注定,七分靠打拼,爱拼才会赢!致力打造专业IT博客。如果你对本博客有任何意见或建议请联系作者,邮箱:blog@mymail.com.cn

JDK 动态代理剖析

逝水无痕 434 0 条

在开发中要对某个类进行增强有许多方法,比如继承或实现接口、装饰者模式、代理模式等,每种方法都有其优缺点。对于继承这种方式来说,代码逻辑简单,缺点就是耦合性太大、不利于后期维护。装饰者模式是一种比较常用的设计模式,比继承增强要灵活,但是代码复杂度要上升许多。代理模式是这几种增强方式中最难于理解的,它通过反射来完成,虽然比较复杂,但却是很多主流框架中经常使用的方式。下面将简要介绍 jdk 动态代理的实现方式和对源代码进行剖析。

jdk动态代理.jpg

简介

jdk 动态代理类位于 Java.lang.reflect 包下,一般主要涉及到以下两个类:

一、interface InvocationHandler :该接口中仅定义了一个方法 Object invoke(Object obj, Method method, Object[] args) 。在实际使用时,第一个参数 obj 一般是指代理类, method 是被代理的方法, args 为该方法的参数数组。这个抽象方法在代理类中动态实现。

二、class Proxy :该类即为动态代理类。在 Proxy 中有几个静态方法供我们调用,其中的 Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 是关键方法,该方法会创建代理类的实例。第一个参数 loader 是被代理类的类加载器,第二个参数 interfaces 是被代理类所实现的接口数组,第三个参数是一个我们自己写的 InvocationHandler 接口的实现类,增强的业务代码就在这个实现类里。

所谓 Dynamic Proxy 是这样一种 class :它是在运行时生成的 class ,在生成它时你必须提供一组 interface 给它,然后该 class 就宣称它实现了这些 interface 。你当然可以把该 class 的实例当作这些 interface 中的任何一个来用。当然啦,这个 Dynamic Proxy 其实就是一个 Proxy ,它不会替你作实质性的工作,在生成它的实例时你必须提供一个 InvocationHandler ,由它接管实际的工作。所以 jdk 动态代理的特点就是必须要有接口才可以,即被代理类必须得实现一个或几个接口。

实现步骤

1、创建一个类实现 InvocationHandler 接口并覆写 invoke 方法

2、创建被代理的类以及接口

3、通过 Proxy 的静态方法 newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个代理

4、通过代理调用方法

示例代码

1、被代理类的接口

package com.example.demo.jdk;

public interface SubjectInterface {

    public void sayHello();
    
    public void sayWorld();
    
    public void sayHelloWorld();
}

2、被代理类

package com.example.demo.jdk;

public class Subject implements SubjectInterface {

    @Override
    public void sayHello() {
        System.out.println("hello");
    }

    @Override
    public void sayWorld() {
        System.out.println("world");
    }

    @Override
    public void sayHelloWorld() {
        System.out.println("hello world");
    }
}

3、测试代码

package com.example.demo.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TestDemo {
    
    public static void main(String[] args) {
        final Subject sub = new Subject();
        SubjectInterface si = (SubjectInterface) Proxy.newProxyInstance(Subject.class.getClassLoader(),
                Subject.class.getInterfaces(), new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if (method.getName().equals("sayHello")) {
                            System.out.println("前置代理增强。。。");
                        }
                        Object obj = method.invoke(sub, args);
                        if (method.getName().equals("sayWorld")) {
                            System.out.println("后置代理增强====");
                        }
                        return obj;
                    }
                    
                });

        si.sayHello();
        si.sayWorld();
        si.sayHelloWorld();
    }
}

执行结果:

前置代理增强。。。
hello

world
后置代理增强====

hello world

结果分析:

执行方法 sayHello() 时会执行 InvocationHandler 接口的匿名对象中的 invoke() 方法,该方法中判断了所调方法的名称满足 "sayHello" 所以先打印了 "前置代理增强。。。" ,然后执行被代理类 Subject 对象的 sayHello() 输出 "hello" ,因不满足第二个判断条件,所以没有输出 "后置代理增强====" 。

在执行 sayWorld()、sayHelloWorld() 方法时逻辑和 sayHello() 是一样的, 所以分别输出了 "world"、"后置代理增强====" 和 "hello world" 。

总结

jdk 动态代理的本质是创建一个代理对象,这个代理对象实现了被代理类的所有接口,在调用被代理类的接口方法时,由于多态性,实际调用的是代理类的包装过的方法。所以依据这个特点,如果一个类没有实现任何接口的话,是不可以使用 jdk 动态代理来进行类增强的,如果仍然想使用动态代理的话,可以利用 CGLib 类库来实现。

Proxy 源码分析(基于 JDK1.8.0_151)

通过前面的讲解我们知道了 jdk 动态代理的关键方法是 Proxy 类的:
Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
那么下面就看看这个方法到底做了什么:

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);
    }

    /*
     * ★★关键方法:获得代理类 Class 对象
     */
    Class<?> cl = getProxyClass0(loader, intfs);

    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }

        // 获得参数类型是 InvocationHandler.class 的构造器
        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;
                }
            });
        }
        // 利用获得的构造器生成代理类实例对象,其中参数为我们传入的 InvocationHandler h 
        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(loader, intfs)

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);
}

接着看 proxyClassCache.get(loader, interfaces)

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
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    // subKeyFactory 类型为 java.lang.reflect.Proxy.KeyFactory.KeyFactory
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        // 经过代码分析可知 supplier 为 Factory 实例对象
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            // ★★关键方法:supplier.get() ==> 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
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                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);
            }
        }
    }
}

下面看一下关键方法 java.lang.reflect.WeakCache.Factory.get()

@Override
public synchronized V get() { // serialize access
    // re-check
    Supplier<V> 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 {
        // 这里的 valueFactory 为 java.lang.reflect.Proxy.ProxyClassFactory 类型
        // ★★关键方法:valueFactory.apply(key, parameter)
        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<V> cacheValue = new CacheValue<>(value);

    // put into reverseMap
    reverseMap.put(cacheValue, Boolean.TRUE);

    // try replacing us with CacheValue (this should always succeed)
    if (!valuesMap.replace(subKey, this, cacheValue)) {
        throw new AssertionError("Should not reach here");
    }

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

下面接着看关键方法 java.lang.reflect.Proxy.ProxyClassFactory.apply(key, parameter)

@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;

    /*
     * ★★关键方法:通过 ProxyGenerator.generateProxyClass() 方法传入参数:代理类的全限定名、代理类的接口数组、修饰符,生成代理类的字节码数组
     */
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
        proxyName, interfaces, accessFlags);
    try {
        // 调用 native 方法生成 Class 类型的代理类对象
        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());
    }
}

通过上面的关键方法 ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags) 可知该方法会生成代理类的字节码数组,那么这个生成的字节码数组转化为 class 文件后到底会长什么样呢? 下面继续分析:

public static void main(String[] args) throws IOException {
    // 下面是一段测试代码来生成 SubjectProxy.class 
    byte[] bytes = ProxyGenerator.generateProxyClass(
            "com.chebing.test.SubjectProxy", Subject.class.getInterfaces(), Modifier.PUBLIC);
    
    FileCopyUtils.copy(bytes, new File("D:/SubjectProxy.class"));
}

SubjectProxy.class 反编译后:

package com.chebing.test;

import com.example.demo.jdk.SubjectInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public class SubjectProxy extends Proxy
  implements SubjectInterface
{
  private static Method m1;
  private static Method m3;
  private static Method m4;
  private static Method m2;
  private static Method m5;
  private static Method m0;

  // 参数类型为 InvocationHandler 的构造函数
  public SubjectProxy(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void sayHello()
    throws 
  {
    try
    {
      // sayHello() 方法实际的执行者是 InvocationHandler h 
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void sayWorld()
    throws 
  {
    try
    {
      this.h.invoke(this, m4, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void sayHelloWorld()
    throws 
  {
    try
    {
      this.h.invoke(this, m5, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      // 反射获取 SubjectInterface 的 sayHello 的 Method 对象
      m3 = Class.forName("com.example.demo.jdk.SubjectInterface").getMethod("sayHello", new Class[0]);
      m4 = Class.forName("com.example.demo.jdk.SubjectInterface").getMethod("sayWorld", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m5 = Class.forName("com.example.demo.jdk.SubjectInterface").getMethod("sayHelloWorld", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

到此我们就可以大致的了解到 jdk 动态代理的实现原理了:代理类是一个实现了被代理类接口的类并且这个类有一个参数类型是 InvocationHandler 的构造器,通过这个构造器生成代理类的实例对象,在调用被代理类的接口方法时,实际调用的是传入的 InvocationHandler 类型参数对象的 invoke() 方法。

与本文相关的文章

发表我的评论
icon_mrgreen.gificon_neutral.gificon_twisted.gificon_arrow.gificon_eek.gificon_smile.gificon_confused.gificon_cool.gificon_evil.gificon_biggrin.gificon_idea.gificon_redface.gificon_razz.gificon_rolleyes.gificon_wink.gificon_cry.gificon_surprised.gificon_lol.gificon_mad.gificon_sad.gificon_exclaim.gificon_question.gif

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址