JDK動態代理深入剖析

2022-11-23 15:00:54

1 基於介面的代理模式

什麼是代理?

簡單來說,代理是指一個物件代替另一個物件去做某些事情。

例如,對於每個程式設計師來說,他都有程式設計的能力:

interface Programmable {
    void developSoftware();
}

對於Java程式設計師,他會編寫Java程式碼:

class JavaProgrammer implements Programmable {
    @Override
    public void developSoftware() {
        System.out.println("編寫Java程式碼");
    }
}

對於JavaScript程式設計師,他會編寫JavaScript程式碼:

class JavaScriptProgrammer implements Programmable {
    @Override
    public void developSoftware() {
        System.out.println("編寫JavaScript程式碼");
    }
}

……

為了完成一個商業軟體,需要各種程式設計師共同共同作業。

因此,網際網路公司出現了:

class ITCompany implements Programmable {
    private List<Programmable> programmers = new LinkedList<>();

    public void recruitProgrammer(Programmable programmer) {
        programmers.add(programmer);
    }
    
    @Override
    public void developSoftware() {
        designProduct();
        programmers.forEach(Programmable::developSoftware);
        operate();
    }
    
    public void designProduct() {
        System.out.println("產品設計");
    }
    
    public void operate() {
        System.out.println("上線運營");
    }
}

此時,網際網路公司對程式設計師進行了代理,並通過提供額外的功能,完善了善軟體開發流程:產品設計 → 編寫程式碼 → 上線運營等。

ITCompany company = new ITCompany();
company.recruitProgrammer(new JavaProgrammer());
company.recruitProgrammer(new JavaScriptProgrammer());
company.developSoftware();

輸出如下:

產品設計
編寫Java程式碼
編寫JavaScript程式碼
上線運營

總結類圖如下:

以上方式被稱為靜態代理模式,步驟如下:

  1. 實現被代理介面。
  2. 儲存被代理物件。
  3. 自定義增強方法。
  4. 實現被代理的方法。

2 JDK動態代理-Proxy

靜態代理有一個明顯的侷限性,那就是它只能固定代理某一類介面。如果需要代理其他介面,就必須重新編寫一個代理類。

java.lang.reflect.Proxy提供了一系列建立動態代理類和範例的靜態方法。

例如,為了建立Programmable介面的代理類,可以按如下方式:

// 1、自定義增強方法
InvocationHandler handler = new MyInvocationHandler();
// 2、建立代理類
Class<?> proxyClass = Proxy.getProxyClass(Programmable.class.getClassLoader(), Programmable.class);
// 3、建立代理物件
Programmable p = (Programmable) proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);

或者:

Programmable p = (Programmable) Proxy.newProxyInstance(Programmable.class.getClassLoader(),
                                                       new Class<?>[] { Programmable.class },
                                                       handler);

很明顯,第二種方式更加簡便(推薦使用)。它其實是對第一種方式進行了封裝,並且做了許多安全處理:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    // 1、安全檢查
    Objects.requireNonNull(h);
    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    // 2、根據介面建立代理類(如果已存在,會直接返回之前建立的代理類)
    Class<?> cl = getProxyClass0(loader, intfs);

    // 3、範例化代理物件
    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) {
    }
}

我們可以發現,Proxy建立代理物件的核心步驟有兩步:

  1. 建立代理類。
  2. 範例化代理物件。

2.1 建立代理類

建立代理類核心方法為java.lang.reflect.Proxy#getProxyClass0

private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }
    return proxyClassCache.get(loader, interfaces);
}
  • java.lang.reflect.Proxy#proxyClassCache成員變數中會快取已建立的代理類(key: 類載入器, parameter: 介面物件陣列, value: 代理類物件)。

    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
    
  • WeakCache#get()方法中會呼叫到如下程式碼:V value = supplier.get();,進而執行valueFactory.apply(key, parameter)。其中valueFactoryProxyClassFactory物件。

ProxyClassFactory#apply()方法中才會真正建立代理類:

public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    // 1、校驗interfaces
    Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
    for (Class<?> intf : interfaces) {
        // 1.1、介面?重複?類載入器可存取?
    }
    String proxyPkg = null;     // package to define proxy class in
    for (Class<?> intf : interfaces) {
        // 1.2、non-public介面是否在同一個包下
    }

    // 2、生成包名
    if (proxyPkg == null) {
       	// if no non-public proxy interfaces, use com.sun.proxy package
    	proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
    }
    long num = nextUniqueNumber.getAndIncrement();
    String proxyName = proxyPkg + proxyClassNamePrefix + num;	// 包名 + $Proxy + 遞增數位

    // 3、生成代理類class檔案
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
    try {
        // 4、動態載入代理類
        return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
    } catch (ClassFormatError e) {
    }
}

核心在於ProxyGenerator#generateProxyClass()

public static byte[] generateProxyClass(final String proxyName, Class<?>[] interfaces, int accessFlags) {
    ProxyGenerator proxyGenerator = new ProxyGenerator(proxyName, interfaces, accessFlags);
    // 生成class檔案
    final byte[] clzBytes = proxyGenerator.generateClassFile();
    if (saveGeneratedFiles) {
        // 儲存class檔案
    }
    return clzBytes;
}

proxyGenerator#generateClassFile()中生成.class檔案:

private byte[] generateClassFile() {
    // 1、新增Object中的方法到proxyMethods快取:hashCode()、equals()、toString()
    this.addProxyMethod(hashCodeMethod, Object.class);
    this.addProxyMethod(equalsMethod, Object.class);
    this.addProxyMethod(toStringMethod, Object.class);
    // 2、新增interfaces中的方法到proxyMethods快取
    Class[] interfaces = this.interfaces;
    int interfacesLength = interfaces.length;
    int i;
    Class interfaceClz;
    for(i = 0; i < interfacesLength; ++i) {
        interfaceClz = interfaces[i];
        Method[] methods = interfaceClz.getMethods();
        int methodsLength = methods.length;
        for(int index = 0; index < methodsLength; ++index) {
            Method m = methods[index];
            this.addProxyMethod(m, interfaceClz);
        }
    }
    try {
        // 3、生成建構函式(形參為:InvocationHandler),新增到methods快取
        this.methods.add(this.generateConstructor());
        proxyMethodsIterator = this.proxyMethods.values().iterator();
        while(proxyMethodsIterator.hasNext()) {
            proxyMethodList = (List)proxyMethodsIterator.next();
            iterator = proxyMethodList.iterator();
            while(iterator.hasNext()) {
                ProxyGenerator.ProxyMethod proxyMethod = (ProxyGenerator.ProxyMethod)iterator.next();
                // 4、生成代理方法成員變數,變數名為m[n],型別為Method,新增到fields快取
                this.fields.add(new ProxyGenerator.FieldInfo(proxyMethod.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                /* 	5、生成代理方法,新增到methods快取。
                	代理方法執行邏輯:
                		建立變數:InvocationHandler物件/當前Method物件/方法原有形參,
                		執行InvocationHandler.invoke()方法
                */
                this.methods.add(proxyMethod.generateMethod());
            }
        }
        // 6、生成靜態初始化方法(沒有形參)
        this.methods.add(this.generateStaticInitializer());
    } catch (IOException interfaces0) {}

    if (this.methods.size() > 65535) {} else if (this.fields.size() > 65535) {
    } else {
        // 7、生成類名
        this.cp.getClass(dotToSlash(this.className));
        // 8、繼承父類別:Proxy
        this.cp.getClass("java/lang/reflect/Proxy");
        // 9、實現所有介面
        interfaces = this.interfaces;
        interfacesLength = interfaces.length;
        for(i = 0; i < interfacesLength; ++i) {
            interfaceClz = interfaces[i];
            this.cp.getClass(dotToSlash(interfaceClz.getName()));
        }
        // 10、寫出到位元組流
        this.cp.setReadOnly();
        ByteArrayOutputStream byteArrOutput = new ByteArrayOutputStream();
        DataOutputStream dataOutput = new DataOutputStream(byteArrOutput);
        try {
            dataOutput.writeInt(-889275714);
            dataOutput.writeShort(0);
            dataOutput.writeShort(49);
            this.cp.write(dataOutput);
            // 存取修飾符
            dataOutput.writeShort(this.accessFlags);
            // 類名
            dataOutput.writeShort(this.cp.getClass(dotToSlash(this.className)));
            // 父類別:Proxy
            dataOutput.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
            // 介面
            dataOutput.writeShort(this.interfaces.length);
            Class[] interfacesArr = this.interfaces;
            int interfacesArrLen = interfacesArr.length;
            for(int i = 0; i < interfacesArrLen; ++i) {
                Class interfaceClz = interfacesArr[i];
                dataOutput.writeShort(this.cp.getClass(dotToSlash(interfaceClz.getName())));
            }
            // 成員變數:即代理方法名-Method
            dataOutput.writeShort(this.fields.size());
            iterator = this.fields.iterator();
            while(iterator.hasNext()) {
                ProxyGenerator.FieldInfo f = (ProxyGenerator.FieldInfo)iterator.next();
                f.write(dataOutput);
            }
            // 代理方法:重新編寫執行邏輯後的方法
            dataOutput.writeShort(this.methods.size());
            iterator = this.methods.iterator();
            while(iterator.hasNext()) {
                ProxyGenerator.MethodInfo m = (ProxyGenerator.MethodInfo)iterator.next();
                m.write(dataOutput);
            }
            dataOutput.writeShort(0);
            return byteArrOutput.toByteArray();
        } catch (IOException var9) {
        }
    }
}

因此,java.lang.reflect.Proxy#getProxyClass0的核心作用如下:

  • 如果快取中,由類載入器loader載入,並且實現給定介面interfaces的代理類已經存在,會直接返回該代理類。
  • 如果代理類不存在,會使用ProxyClassFactory建立新的代理類。

例如,對於某些介面:

public interface IT1 {
    void fun1();
}
public interface IT2 {
    Object fun2(Object[] args);
}

生成代理類的虛擬碼如下:

package com.sun.proxy|non-public介面所在包
[public] final class $Proxy[n]
    extends Proxy
    implements IT1, IT2 {
    protected InvocationHandler h;	// Proxy類中
    private static Method m0;	// hashCode
    private static Method m1;	// equals
    private static Method m2;	// toString
    private static Method m3;	// fun1
    private static Method m4;	// fun2
    public void hashCode() {
        InvocationHandler handler = this.h;
        Method m = this.mo;
        handler.invoke(this, m, null);
    }
    public void equals(Object obj) {
        InvocationHandler handler = this.h;
        Method m = this.m1;
        handler.invoke(this, m, obj);
    }
    public void toString() {
        InvocationHandler handler = this.h;
        Method m = this.m2;
        handler.invoke(this, m, null);
    }
    public void fun1() {
        InvocationHandler handler = this.h;
        Method m = this.m3;
        handler.invoke(this, m, null);
    }
    public Object fun2(Object[] args) {
        InvocationHandler handler = this.h;
        Method m = this.m4;
        Object rs = handler.invoke(this, m, args);
        return rs;
    }
}
  • 如果介面全為public,則代理類修飾符為public final。此時類名為com.sun.proxy.$Proxy[n]
  • 如果介面中存在non-public介面,且全位於同一個包下,則代理類修飾符為final。此時類名為non-public介面所在包.$Proxy[n]
  • 需要注意的是,Object物件中只有hashCode()equals()toString()這三個方法會被重寫。
  • 動態生成的代理類修飾符為final,這意味著它不能被繼承。

例如,我們通過以下方式生成代理類,並列印出相關資料:

Real real = new Real();
Object proxyInstance = Proxy.newProxyInstance(ProxyDemo.class.getClassLoader(),
        new Class[]{IT1.class, IT2.class},
        new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("proxy method: " + method.getName());
                return method.invoke(real, args);
            }
        });
// 獲取當前代理類的屬性
System.out.println("代理類成員變數:");
Field[] fields = proxyInstance.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
    StringBuilder sb = new StringBuilder();
    Field field = fields[i];
    // 修飾符
    int modifiers = field.getModifiers();
    sb.append(Modifier.toString(modifiers)).append(" ");
    field.setAccessible(true);
    // 成員變數型別&變數名
    sb.append(field.getType().getName()).append(" ").append(field.getName()).append(":");
    Method m = (Method) field.get(Method.class);
    m.setAccessible(true);
    // 方法名
    sb.append(m.getName());
    System.out.println(sb.toString());
}
System.out.println("Proxy類成員變數:");
Field[] superFields = proxyInstance.getClass().getSuperclass().getDeclaredFields();
for (int i = 0; i < superFields.length; i++) {
    StringBuilder sb = new StringBuilder();
    Field field = superFields[i];
    // 修飾符
    int modifiers = field.getModifiers();
    sb.append(Modifier.toString(modifiers)).append(" ");
    field.setAccessible(true);
    // 成員變數型別&變數名
    sb.append(field.getType().getName()).append(" ").append(field.getName());
    System.out.println(sb.toString());
}
System.out.println("代理類方法:");
Method[] methods = proxyInstance.getClass().getMethods();
for (int i = 0; i < methods.length; i++) {
    StringBuilder sb = new StringBuilder();
    Method method = methods[i];
    int modifiers = method.getModifiers();
    sb.append(Modifier.toString(modifiers)).append(" ");
    sb.append(method.getReturnType().getName()).append(" ").append(method.getName());
    System.out.println(sb.toString());
}
System.out.println("代理類建構函式:");
Constructor<?>[] constructors = proxyInstance.getClass().getConstructors();
for (int i = 0; i < constructors.length; i++) {
    StringBuilder sb = new StringBuilder();
    Constructor constructor = constructors[i];
    int modifiers = constructor.getModifiers();
    sb.append(Modifier.toString(modifiers)).append(" ");
    sb.append(constructor.getName()).append("(");
    Class[] parameterTypes = constructor.getParameterTypes();
    for (int i1 = 0; i1 < parameterTypes.length; i1++) {
        sb.append(parameterTypes[i1].getName());
        if (i1 < parameterTypes.length - 1) {
            sb.append(",");
        }
    }
    sb.append(")");
    System.out.println(sb.toString());
}

列印結果如下:

代理類成員變數:
private static java.lang.reflect.Method m1:equals
private static java.lang.reflect.Method m3:fun1
private static java.lang.reflect.Method m2:toString
private static java.lang.reflect.Method m4:fun2
private static java.lang.reflect.Method m0:hashCode
Proxy父類別成員變數:
private static final long serialVersionUID
private static final [Ljava.lang.Class; constructorParams
private static final java.lang.reflect.WeakCache proxyClassCache
protected java.lang.reflect.InvocationHandler h
private static final java.lang.Object key0
代理類方法:
public final boolean equals
public final java.lang.String toString
public final int hashCode
public final void fun1
public final java.lang.Object fun2
public static boolean isProxyClass
public static java.lang.reflect.InvocationHandler getInvocationHandler
public static transient java.lang.Class getProxyClass
public static java.lang.Object newProxyInstance
public final void wait
public final void wait
public final native void wait
public final native java.lang.Class getClass
public final native void notify
public final native void notifyAll
代理類建構函式:
public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)

2.2 範例化代理類物件

有了以上的基礎,我們應該能很容易理解接下來的操作了。

// 1、根據型別獲取建構函式:形參為InvocationHandler
final Constructor<?> cons = cl.getConstructor(constructorParams);
// 2、通過建構函式範例化代理物件,並返回
final InvocationHandler ih = h;
return cons.newInstance(new Object[]{h});

2.3 總結

使用JDK-動態代理Proxy的方式如下:

  1. 實現InvocationHandler介面,其中invoke()方法為代理類實際執行的方法。
  2. 呼叫Proxy.newProxyInstance()方法,傳入類載入器、代理介面陣列和InvocationHandler物件。

最終生成代理類的類圖如下:

3 範例

3.1 Spring中的JDK動態代理

Spring使用org.springframework.aop.framework.ProxyFactoryBean進行AOP動態代理:

public Object getObject() throws BeansException {
   initializeAdvisorChain();
   if (isSingleton()) {
      return getSingletonInstance();
   }
   else {
      if (this.targetName == null) {
         logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
               "Enable prototype proxies by setting the 'targetName' property.");
      }
      return newPrototypeInstance();
   }
}

其最終會呼叫org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)方法,進行JDK動態代理:

public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isTraceEnabled()) {
      logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
   }
   return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}

JdkDynamicAopProxy是Spring中JDK動態代理的核心類,它既作為動態代理的工具類,又作為InvocationHandler實現類定義了代理方法執行邏輯:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

其中實現的invoke()方法如下:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;

   TargetSource targetSource = this.advised.targetSource;
   Object target = null;

   try {
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
         // The target does not implement the equals(Object) method itself.
         return equals(args[0]);
      }
      else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
         // The target does not implement the hashCode() method itself.
         return hashCode();
      }
      else if (method.getDeclaringClass() == DecoratingProxy.class) {
         // There is only getDecoratedClass() declared -> dispatch to proxy config.
         return AopProxyUtils.ultimateTargetClass(this.advised);
      }
      else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
            method.getDeclaringClass().isAssignableFrom(Advised.class)) {
         // Service invocations on ProxyConfig with the proxy config...
         return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      }

      Object retVal;

      if (this.advised.exposeProxy) {
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }

      // Get as late as possible to minimize the time we "own" the target,
      // in case it comes from a pool.
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);

      // Get the interception chain for this method.
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      // Check whether we have any advice. If we don't, we can fallback on direct
      // reflective invocation of the target, and avoid creating a MethodInvocation.
      if (chain.isEmpty()) {
         // We can skip creating a MethodInvocation: just invoke the target directly
         // Note that the final invoker must be an InvokerInterceptor so we know it does
         // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         // We need to create a method invocation...
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
         retVal = invocation.proceed();
      }

      // Massage return value if necessary.
      Class<?> returnType = method.getReturnType();
      if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
         // Special case: it returned "this" and the return type of the method
         // is type-compatible. Note that we can't help if the target sets
         // a reference to itself in another returned object.
         retVal = proxy;
      }
      else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
         throw new AopInvocationException(
               "Null return value from advice does not match primitive return type for: " + method);
      }
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         // Must have come from TargetSource.
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

3.2 Mybatis中的JDK動態代理

org.apache.ibatis.session.SqlSession#getMapper可以獲取動態生成的mapper範例:

<T> T getMapper(Class<T> type);

其底層會呼叫org.apache.ibatis.binding.MapperRegistry#getMapper

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  if (mapperProxyFactory == null) {
    throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  }
  try {
    return mapperProxyFactory.newInstance(sqlSession);
  } catch (Exception e) {
    throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  }
}

通過org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.session.SqlSession)最終生成代理類:

public T newInstance(SqlSession sqlSession) {
  final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
  return newInstance(mapperProxy);
}

protected T newInstance(MapperProxy<T> mapperProxy) {
  return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

其中org.apache.ibatis.binding.MapperProxyInvocationHandler實現類,其invoke()方法如下:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  try {
    if (Object.class.equals(method.getDeclaringClass())) {
      return method.invoke(this, args);
    } else {
      return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
    }
  } catch (Throwable t) {
    throw ExceptionUtil.unwrapThrowable(t);
  }
}

private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
  try {
    return MapUtil.computeIfAbsent(methodCache, method, m -> {
      if (m.isDefault()) {
        try {
          if (privateLookupInMethod == null) {
            return new DefaultMethodInvoker(getMethodHandleJava8(method));
          } else {
            return new DefaultMethodInvoker(getMethodHandleJava9(method));
          }
        } catch (IllegalAccessException | InstantiationException | InvocationTargetException
            | NoSuchMethodException e) {
          throw new RuntimeException(e);
        }
      } else {
        return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
      }
    });
  } catch (RuntimeException re) {
    Throwable cause = re.getCause();
    throw cause == null ? re : cause;
  }
}

private MethodHandle getMethodHandleJava9(Method method)
    throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
  final Class<?> declaringClass = method.getDeclaringClass();
  return ((Lookup) privateLookupInMethod.invoke(null, declaringClass, MethodHandles.lookup())).findSpecial(
      declaringClass, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()),
      declaringClass);
}
  • 對於Object方法,它不會進行代理。
  • 對於非Object方法,會找到對應的Method物件,然後傳入引數進行呼叫。