我是一段不羁的公告!
记得给艿艿这 3 个项目加油,添加一个 STAR 噢。
https://github.com/YunaiV/SpringBoot-Labs
https://github.com/YunaiV/onemall
https://github.com/YunaiV/ruoyi-vue-pro

精尽 Dubbo 源码分析 —— 动态代理(一)之 Javassist

本文基于 Dubbo 2.6.1 版本,望知悉。

1. 概述

本文分享 Dubbo 动态代理的实现。

《Dubbo 用户指南 —— schema 配置参考手册》 中,我们可以看到 <dubbo:service /><dubbo:reference /> 标签中,可以通过 "proxy" 属性,可以配置动态代理的生成方式:

生成动态代理方式,可选:jdk / javassist

从说明中,我们可以看到,Dubbo 实现了两种方式生成代理:

  • Javassit
  • JDK

🙂 本文分享 Javassist 实现动态代理的源码;涉及代码如下:

  • dubbo-common 模块的 bytecode 包。
  • dubbo-rpc-api 模块的 proxy 包。

下一篇文章分享 JDK 实现动态代理的源码。

2. 性能

在分享具体实现之前,可能有胖友对性能方面感兴趣,可以看看如下的内容:

3. 整体流程

😈 瞎比比了这么多,我们开始进入正题了。相信很多胖友对动态代理的概念已经理解(如果暂时不理解,请 Google 下),那么 Dubbo 对它们使用在哪呢?见下图:

菜逼老王

旁白君:本图暂不考虑集群容错、网络调用、序列化反序列等。

  • 在 Dubbo 中,我们使用 Service 接口,作为服务 API 的契约。
  • 在 Consumer 中,我们调用 Service 接口的方法时,实际调用的是 Dubbo 动态代理。下面先一起来看一个生成的 proxy 代码的示例:

     1: package com.alibaba.dubbo.common.bytecode;
    2:
    3: import com.alibaba.dubbo.demo.DemoService;
    4: import com.alibaba.dubbo.rpc.service.EchoService;
    5: import java.lang.reflect.InvocationHandler;
    6: import java.lang.reflect.Method;
    7:
    8: public class proxy0
    9: implements ClassGenerator.DC, EchoService, DemoService
    10: {
    11: public static Method[] methods;
    12: private InvocationHandler handler;
    13:
    14: public void bye(Object paramObject)
    15: {
    16: Object[] arrayOfObject = new Object[1];
    17: arrayOfObject[0] = paramObject;
    18: Object localObject = this.handler.invoke(this, methods[0], arrayOfObject);
    19: }
    20:
    21: public String sayHello(String paramString)
    22: {
    23: Object[] arrayOfObject = new Object[1];
    24: arrayOfObject[0] = paramString;
    25: Object localObject = this.handler.invoke(this, methods[1], arrayOfObject);
    26: return (String)localObject;
    27: }
    28:
    29: public Object $echo(Object paramObject)
    30: {
    31: Object[] arrayOfObject = new Object[1];
    32: arrayOfObject[0] = paramObject;
    33: Object localObject = this.handler.invoke(this, methods[2], arrayOfObject);
    34: return (Object)localObject;
    35: }
    36:
    37: public proxy0() {}
    38:
    39: public proxy0(InvocationHandler paramInvocationHandler)
    40: {
    41: this.handler = paramInvocationHandler;
    42: }
    43: }
    • 该类通过 dubbo-common 模块的 bytecode 模块的 Proxy 类,自动生成,使用 Javassist 技术。
    • 生成的 proxy 类会实现我们定义的 Service 接口( 例如,此处是 DemoService )。
    • #bye(Object)#sayHello(Object) 方法,是我们定义在 DemoService 的接口方法,在生成的 proxy 类中,实现这些定义在接口中的方法,收拢统一调用 java.lang.reflect.InvocationHandler#invoke(proxy, method, args) 方法。通过这样的方式,可以调用到最终的 Invoker#invoke(Invocation) 方法,实现 RPC 调用。
    • 注意,此处我们一直用的 proxy 一直是小写的,这是为什么呢?请见下文大写的 Proxy 类。
  • 在 Provider 中,XXXProtocol 会获得被调用的 Exporter 对象,从而获得到 Invoker 对象。但是呢,Invoker 对象实际和 Service 实现对象,是无法直接调用,需要有中间的一层 Wrapper 来代理分发到 Service 对应的方法。下面我们来看一个生成的 Wrapper 代码的示例:

      1: package com.alibaba.dubbo.common.bytecode;
    2:
    3: import com.alibaba.dubbo.demo.provider.DemoDAO;
    4: import com.alibaba.dubbo.demo.provider.DemoServiceImpl;
    5: import java.lang.reflect.InvocationTargetException;
    6: import java.util.Map;
    7:
    8: public class Wrapper1
    9: extends Wrapper
    10: implements ClassGenerator.DC
    11: {
    12: public static String[] pns;
    13: public static Map pts;
    14: public static String[] mns;
    15: public static String[] dmns;
    16: public static Class[] mts0;
    17: public static Class[] mts1;
    18: public static Class[] mts2;
    19:
    20: public String[] getPropertyNames()
    21: {
    22: return pns;
    23: }
    24:
    25: public boolean hasProperty(String paramString)
    26: {
    27: return pts.containsKey(paramString);
    28: }
    29:
    30: public Class getPropertyType(String paramString)
    31: {
    32: return (Class)pts.get(paramString);
    33: }
    34:
    35: public String[] getMethodNames()
    36: {
    37: return mns;
    38: }
    39:
    40: public String[] getDeclaredMethodNames()
    41: {
    42: return dmns;
    43: }
    44:
    45: public void setPropertyValue(Object paramObject1, String paramString, Object paramObject2)
    46: {
    47: DemoServiceImpl w;
    48: try
    49: {
    50: w = (DemoServiceImpl)paramObject1;
    51: }
    52: catch (Throwable localThrowable)
    53: {
    54: throw new IllegalArgumentException(localThrowable);
    55: }
    56: if (paramString.equals("test01"))
    57: {
    58: w.test01 = ((String)paramObject2);
    59: return;
    60: }
    61: if (paramString.equals("demoDAO"))
    62: {
    63: localDemoServiceImpl.setDemoDAO((DemoDAO)paramObject2);
    64: return;
    65: }
    66: throw new NoSuchPropertyException("Not found property \"" + paramString + "\" filed or setter method in class com.alibaba.dubbo.demo.provider.DemoServiceImpl.");
    67: }
    68:
    69: public Object getPropertyValue(Object paramObject, String paramString)
    70: {
    71: DemoServiceImpl w;
    72: try
    73: {
    74: w = (DemoServiceImpl)paramObject;
    75: }
    76: catch (Throwable localThrowable)
    77: {
    78: throw new IllegalArgumentException(localThrowable);
    79: }
    80: if (paramString.equals("test01")) {
    81: return localDemoServiceImpl.test01;
    82: }
    83: throw new NoSuchPropertyException("Not found property \"" + paramString + "\" filed or setter method in class com.alibaba.dubbo.demo.provider.DemoServiceImpl.");
    84: }
    85:
    86: public Object invokeMethod(Object paramObject, String paramString, Class[] paramArrayOfClass, Object[] paramArrayOfObject)
    87: throws InvocationTargetException
    88: {
    89: DemoServiceImpl w;
    90: try
    91: {
    92: w = (DemoServiceImpl)paramObject;
    93: }
    94: catch (Throwable localThrowable1)
    95: {
    96: throw new IllegalArgumentException(localThrowable1);
    97: }
    98: try
    99: {
    100: if ("sayHello".equals(paramString) && paramArrayOfClass.length == 1) {
    101: return w.sayHello((String)paramArrayOfObject[0]);
    102: }
    103: if ("bye".equals(paramString) && paramArrayOfClass.length == 1)
    104: {
    105: w.bye((Object)paramArrayOfObject[0]);
    106: return null;
    107: }
    108: if ("setDemoDAO".equals(paramString) && paramArrayOfClass.length == 1)
    109: {
    110: w.setDemoDAO((DemoDAO)paramArrayOfObject[0]);
    111: return null;
    112: }
    113: }
    114: catch (Throwable localThrowable2)
    115: {
    116: throw new InvocationTargetException(localThrowable2);
    117: }
    118: throw new NoSuchMethodException("Not found method \"" + paramString + "\" in class com.alibaba.dubbo.demo.provider.DemoServiceImpl.");
    119: }
    120: }
    • 该类通过 dubbo-common 模块的 bytecode 模块的 Wrapper 类,自动生成,使用 Javassist 技术。
    • 不同于生成的 proxy类,不实现 Service 接口类,而是在 #invokeMethod(paramObject, paramString, paramArrayOfClass, paramArrayOfObject) 方法,提供给 Invoker#invoke(invocation) 中调用,统一分发请求到 Service 对应的方法。从职能上来看,有一点像硬编码的 Controller 。
    • 一个生成的 Wrapper类,只对应一个 Service ,从第 75 行的代码,我们也可以看出。

4. ProxyFactory

com.alibaba.dubbo.rpc.ProxyFactory ,代理工厂接口。

《精尽 Dubbo 源码分析 —— 核心流程一览》「4.5 ProxyFactory」,已经分享,胖友点击查看。

ProxyFactory 子类

4.1 AbstractProxyFactory

com.alibaba.dubbo.rpc.proxy.AbstractProxyFactory ,实现 ProxyFactory 接口,代理工厂抽象类。代码如下:

 1: public abstract class AbstractProxyFactory implements ProxyFactory {
2:
3: public <T> T getProxy(Invoker<T> invoker) throws RpcException {
4: Class<?>[] interfaces = null;
5: // TODO 8022 芋艿
6: String config = invoker.getUrl().getParameter("interfaces");
7: if (config != null && config.length() > 0) {
8: String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);
9: if (types != null && types.length > 0) {
10: interfaces = new Class<?>[types.length + 2];
11: interfaces[0] = invoker.getInterface();
12: interfaces[1] = EchoService.class;
13: for (int i = 0; i < types.length; i++) {
14: interfaces[i + 1] = ReflectUtils.forName(types[i]);
15: }
16: }
17: }
18: // 增加 EchoService 接口,用于回生测试。参见文档《回声测试》http://dubbo.apache.org/zh-cn/docs/user/demos/echo-service.html
19: if (interfaces == null) {
20: interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
21: }
22: return getProxy(invoker, interfaces);
23: }
24:
25: public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);
26:
27: }
  • 可以看到,该抽象类,主要是实现了 #getProxy(invoker) 方法,获得需要生成代理的接口们。

    • 第 5 至 17 行: TODO 8022 芋艿
    • 第 18 至 21 行:在原有 Invoker 对应关联的 Service 接口之上,增加 EchoService 接口。

      FROM 《Dubbo 用户指南 —— 回声测试》

      回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,能够测试整个调用是否通畅,可用于监控。
      所有服务自动实现 EchoService 接口,只需将任意服务引用强制转型为 EchoService,即可使用。

    • 第 22 行:调用 #getProxy(invoker, types) 抽象方法,获得 Proxy 对象。

4.2 StubProxyFactoryWrapper

com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper ,实现 ProxyFactory 接口,Stub 代理工厂 Wrapper 实现类,基于 Dubbo SPI Wrapper 机制加载。

🙂 该类,不在本文的范畴内,感兴趣的胖友可以先看下 《Dubbo 用户指南 —— 本地存根》 。后续,我们单独开文章分享。

4.3 JavassistProxyFactory

com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory ,实现 AbstractProxyFactory 抽象类,基于 Javassist 代理工厂实现类。代码如下:

 1: public class JavassistProxyFactory extends AbstractProxyFactory {
2:
3: @SuppressWarnings("unchecked")
4: public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
5: return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
6: }
7:
8: public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
9: // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
10: // TODO Wrapper类不能正确处理带$的类名
11: final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
12: return new AbstractProxyInvoker<T>(proxy, type, url) {
13: @Override
14: protected Object doInvoke(T proxy, String methodName,
15: Class<?>[] parameterTypes,
16: Object[] arguments) throws Throwable {
17: return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
18: }
19: };
20: }
21:
22: }
  • #getProxy(invoker, interfaces) 方法
    • 第 5 行:调用 Proxy#getProxy(interface) 方法,获得 Proxy 对象。
    • 第 5 行:调用 Proxy#newInstance(InvocationHandler) 方法,获得 proxy 对象。其中传入的参数是 InvokerInvocationHandler 类,通过这样的方式,让 proxy 和真正的逻辑代码解耦。
  • #getInvoker(proxy, type, url) 方法
    • 第 11 行:调用 Wrapper#getWrapper(Class<?>) 方法,获得 Wrapper 对象。
    • 第 12 至 19 行:创建 AbstractProxyInvoker 对象,实现 #doInvoke(...) 方法。在该方法中,调用 Wrapper#invokeMethod(...) 方法,从而调用 Service 的方法。

5. InvokerInvocationHandler

com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler ,实现 java.lang.reflect.InvocationHandler 接口,代码如下:

 1: public class InvokerInvocationHandler implements InvocationHandler {
2:
3: /**
4: * Invoker 对象
5: */
6: private final Invoker<?> invoker;
7:
8: public InvokerInvocationHandler(Invoker<?> handler) {
9: this.invoker = handler;
10: }
11:
12: @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
13: String methodName = method.getName();
14: Class<?>[] parameterTypes = method.getParameterTypes();
15: // wait 等方法,直接反射调用
16: if (method.getDeclaringClass() == Object.class) {
17: return method.invoke(invoker, args);
18: }
19: // 基础方法,不使用 RPC 调用
20: if ("toString".equals(methodName) && parameterTypes.length == 0) {
21: return invoker.toString();
22: }
23: if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
24: return invoker.hashCode();
25: }
26: if ("equals".equals(methodName) && parameterTypes.length == 1) {
27: return invoker.equals(args[0]);
28: }
29: // RPC 调用
30: return invoker.invoke(new RpcInvocation(method, args)).recreate();
31: }
32:
33: }
  • invoker 属性,Invoker 对象,用于在 #invoke() 方法调用。
  • #invoke(proxy, method, args) 实现方法,核心逻辑是调用 Invoker#invoke(invocation) 方法,进行 RPC 调用。

    • 第 16 至 18 行:处理 #wait() #notify() 等方法,进行反射调用。
    • 第 20 至 28 行:处理 #toString() #hashCode() 等方法,使用 Invoker 对象的方法,不进行 RPC 调用。
    • 第 30 行:调用 Invoker#invoke(invocation) 方法,核心逻辑,进行 RPC 调用。
    • 第 30 行:调用 Result#recreate() 方法,回放调用结果。代码如下:

      // RpcResult.java
      public Object recreate() throws Throwable {
      // 有异常,抛出异常
      if (exception != null) {
      throw exception;
      }
      // 无异常,返回结果
      return result;
      }
      • x

🙂 通过 InvokerInvocationHandler ,可以实现 Proxy 和真正的逻辑解耦。

6. AbstractProxyInvoker

com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker ,实现 Invoker 接口,代理 Invoker 对象的抽象类。

6.1 属性

/**
* 代理的对象,一般是 Service 实现对象
*/
private final T proxy;
/**
* 接口类型,一般是 Service 接口
*/
private final Class<T> type;
/**
* URL 对象,一般是暴露服务的 URL 对象
*/
private final URL url;

public AbstractProxyInvoker(T proxy, Class<T> type, URL url) {
if (proxy == null) {
throw new IllegalArgumentException("proxy == null");
}
if (type == null) {
throw new IllegalArgumentException("interface == null");
}
if (!type.isInstance(proxy)) { //
throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type);
}
this.proxy = proxy;
this.type = type;
this.url = url;
}

🙂 胖友,请看代码上的注释。

6.2 invoke

1: public Result invoke(Invocation invocation) throws RpcException {
2: try {
3: return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
4: } catch (InvocationTargetException e) {
5: return new RpcResult(e.getTargetException());
6: } catch (Throwable e) {
7: throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
8: }
9: }
  • 第 3 行:调用 #doInvoke(..) 抽象方法,执行调用,返回调用结果。#doInvoke(...) 方法,代码如下:

    /**
    * 执行调用
    *
    * @param proxy 代理的对象
    * @param methodName 方法名
    * @param parameterTypes 方法参数类型数组
    * @param arguments 方法参数数组
    * @return 调用结果
    * @throws Throwable 发生异常
    */
    protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;
  • 第 3 行:创建 RpcResult 对象,将结果包装返回。

  • 第 5 行:发生 InvocationTargetException 异常,创建 RpcResult 对象包装。

7. bytecode

dubbo-common 模块的 bytecode 包,基于 Javassit 库,动态编译,实现提供了通用的的动态代理实现。所以本小节,从动态编译的角度上来看,在内容上,和 《精尽 Dubbo 源码分析 —— 动态编译(一)之 Javassist》 有一定的相似。

7.1 ClassGenerator

com.alibaba.dubbo.common.bytecode.ClassGenerator ,类生成器,基于 Javassist 实现。

笔者在 《TCC-Transaction 源码分析 —— Dubbo 支持》「2.1.3 TccProxy & TccClassGenerator」 已经详细分享,基本类似,胖友瞅瞅噢。

7.3 Proxy

com.alibaba.dubbo.common.bytecode.Proxy ,代理抽象类,用于创建 Proxy 和 proxy 对象。

笔者在 《TCC-Transaction 源码分析 —— Dubbo 支持》「2.1.3 TccProxy & TccClassGenerator」 已经详细分享,基本类似,胖友瞅瞅噢。


如下是一个生成的 Proxy 代码的示例,代码如下:

public class Proxy0 extends Proxy implements ClassGenerator.DC {

public Object newInstance(InvocationHandler paramInvocationHandler) {
return new proxy0(paramInvocationHandler);
}

}
  • 生成的Proxy 实现 Proxy 抽象类,是创建 生成的proxy 的工厂(一一对应)。例如,Proxy0 创建 proxy0 对象。
  • #newInstance(InvocationHandler) 方法,创建 生成的proxy 的方法。

7.4 Wrapper

com.alibaba.dubbo.common.bytecode.Wrapper ,Wrapper 抽象类,用于创建某个对象的方法调用的包装器,以避免反射调用,提高性能。即:

// 反射
Method#invoke(Object instance, Object[] args)

// 优化成===>

// Wrapper
Wrapper#invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args)
  • 为什么会提高性能呢?看到上文的 Wrapper 代理的示例,相信胖友已经明白。

7.4.1 抽象方法

在自动生成 Wrapper 类时,需要实现如下抽象方法:

abstract public String[] getPropertyNames();
abstract public Class<?> getPropertyType(String pn);

abstract public boolean hasProperty(String name);
abstract public Object getPropertyValue(Object instance, String pn) throws NoSuchPropertyException, IllegalArgumentException;
abstract public void setPropertyValue(Object instance, String pn, Object pv) throws NoSuchPropertyException, IllegalArgumentException;

abstract public String[] getMethodNames();
abstract public String[] getDeclaredMethodNames();

/**
* invoke method.
*
* 调用方法
*
* @param instance instance.
* 被调用的对象
* @param mn method name.
* 方法名
* @param types 参数类型数组
* @param args argument array.
* 参数数组
* @return return value.
* 返回值
*/
abstract public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;

7.4.2 getWrapper

#getWrapper(c) 方法,根据指定类,获得 Wrapper 对象。代码如下:

 1: public static Wrapper getWrapper(Class<?> c) {
2: // 判断是否继承 ClassGenerator.DC.class ,如果是,拿到父类,避免重复包装
3: while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
4: c = c.getSuperclass();
5:
6: // 指定类为 Object.class
7: if (c == Object.class)
8: return OBJECT_WRAPPER;
9:
10: // 从缓存中获得 Wrapper 对象
11: Wrapper ret = WRAPPER_MAP.get(c);
12: // 创建 Wrapper 对象,并添加到缓存
13: if (ret == null) {
14: ret = makeWrapper(c);
15: WRAPPER_MAP.put(c, ret);
16: }
17: return ret;
18: }
  • 第 3 至 4 行:判断是否已经继承了 ClassGenerator.DC.class ,如果是,拿到父类,避免重复包装
  • 第 7 至 8 行:若指定类为 Object.class ,返回 OBJECT_WRAPPER 对象。
  • 第 11 行:从缓存 WRAPPER_MAP 中,获得 Wrapper 对象。WRAPPER_MAP 代码如下:

    /**
    * Wrapper 对象缓存
    * key :Wrapper 类。
    * value :Proxy 对象
    */
    private static final Map<Class<?>, Wrapper> WRAPPER_MAP = new ConcurrentHashMap<Class<?>, Wrapper>(); //class wrapper map
  • 第 13 至 16 行:调用 #makeWrapper(Class<?>) 方法,创建 Wrapper 对象,并添加到缓存。

7.4.3 makeWrapper

#makeWrapper(Class<?>) 方法,创建 Wrapper 对象。代码如下:

旁白君:实现上,和 Proxy 差不过的,只生成一个 Wrapper 类。

  1: private static Wrapper makeWrapper(Class<?> c) {
2: // 非私有类
3: if (c.isPrimitive())
4: throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
5:
6: // 类名
7: String name = c.getName();
8: // 类加载器
9: ClassLoader cl = ClassHelper.getClassLoader(c);
10:
11: // 设置属性方法 `#setPropertyValue(o, n, v)` 的开头的代码
12: StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
13: // 获得属性方法 `#getPropertyValue(o, n)` 的开头的代码
14: StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
15: // 调用方法 `#invokeMethod(o, n, p, v)` 的开头的代码
16: StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
17:
18: // 添加每个方法的,被调用对象的类型转换的代码
19: c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
20: c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
21: c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
22:
23: // 属性名与属性名的集合,用于 `#hasProperty(...)` `#setPropertyValue(...)` `getPropertyValue(...)` 方法。
24: Map<String, Class<?>> pts = new HashMap<String, Class<?>>(); // <property name, property types>
25: // 方法签名与方法对象的集合,用于 `#invokeMethod(..)` 方法。
26: Map<String, Method> ms = new LinkedHashMap<String, Method>(); // <method desc, Method instance>
27: // 方法名数组用于 `#getMethodNames()` 方法。
28: List<String> mns = new ArrayList<String>(); // method names.
29: // 定义的方法名数组,用于 `#getDeclaredMethodNames()` 方法。
30: List<String> dmns = new ArrayList<String>(); // declaring method names.
31:
32: // 循环 public 属性,添加每个属性的设置和获得分别到 `#setPropertyValue(o, n, v)` 和 `#getPropertyValue(o, n)` 的代码
33: // get all public field.
34: for (Field f : c.getFields()) {
35: String fn = f.getName();
36: Class<?> ft = f.getType();
37: if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers())) // 排除 static 和 transient
38: continue;
39:
40: c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
41: c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
42: // 添加到 `pts` 中
43: pts.put(fn, ft);
44: }
45:
46: Method[] methods = c.getMethods();
47: // 如果有方法,添加 `#invokeMethod(o, n, p, v)` 的 try 的代码
48: // get all public method.
49: boolean hasMethod = hasMethods(methods);
50: if (hasMethod) {
51: c3.append(" try{");
52: }
53: for (Method m : methods) {
54: // 跳过来自 Object 的内置方法
55: if (m.getDeclaringClass() == Object.class) //ignore Object's method.
56: continue;
57:
58: String mn = m.getName(); // 方法名
59: // 使用方法名 + 方法参数长度来判断
60: c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
61: int len = m.getParameterTypes().length;
62: c3.append(" && ").append(" $3.length == ").append(len);
63:
64: // 若相同方法名存在多个,增加参数类型数组的比较判断
65: boolean override = false;
66: for (Method m2 : methods) {
67: if (m != m2 && m.getName().equals(m2.getName())) {
68: override = true;
69: break;
70: }
71: }
72: if (override) {
73: if (len > 0) {
74: for (int l = 0; l < len; l++) {
75: c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
76: .append(m.getParameterTypes()[l].getName()).append("\")");
77: }
78: }
79: }
80:
81: c3.append(" ) { ");
82:
83: // 添加调用对象的对应方法的代码
84: if (m.getReturnType() == Void.TYPE)
85: c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
86: else
87: c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");
88:
89: c3.append(" }");
90:
91: // 添加到 `mns` 中
92: mns.add(mn);
93: // 添加到 `dmns` 中
94: if (m.getDeclaringClass() == c)
95: dmns.add(mn);
96: // 添加到 `ms` 中
97: ms.put(ReflectUtils.getDesc(m), m);
98: }
99: // 如果有方法,添加 `#invokeMethod(o, n, p, v)` 的 catch 的代码
100: if (hasMethod) {
101: c3.append(" } catch(Throwable e) { ");
102: c3.append(" throw new java.lang.reflect.InvocationTargetException(e); ");
103: c3.append(" }");
104: }
105: // 添加 `#invokeMethod(o, n, p, v)` 的未匹配到方法的代码
106: c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");
107:
108: // 循环 setting/getting 方法,添加每个属性的设置和获得分别到 `#setPropertyValue(o, n, v)` 和 `#getPropertyValue(o, n)` 的代码
109: // deal with get/set method.
110: Matcher matcher;
111: for (Map.Entry<String, Method> entry : ms.entrySet()) {
112: String md = entry.getKey();
113: Method method = entry.getValue();
114: if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
115: String pn = propertyName(matcher.group(1));
116: c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
117: // 添加到 `pts` 中
118: pts.put(pn, method.getReturnType());
119: } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
120: String pn = propertyName(matcher.group(1));
121: c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
122: // 添加到 `pts` 中
123: pts.put(pn, method.getReturnType());
124: } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) { // 不支持 public T setName(String name) { this.name = name; return this;} 这种返回 this 的形式。
125: Class<?> pt = method.getParameterTypes()[0];
126: String pn = propertyName(matcher.group(1));
127: c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");
128: // 添加到 `pts` 中
129: pts.put(pn, pt);
130: }
131: }
132: c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
133: c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
134:
135: // make class
136: long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
137: // 创建 ClassGenerator 对象
138: ClassGenerator cc = ClassGenerator.newInstance(cl);
139: // 设置类名
140: cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
141: // 设置父类为 Wrapper.class
142: cc.setSuperClass(Wrapper.class);
143:
144: // 添加构造方法,参数 空
145: cc.addDefaultConstructor();
146: // 添加静态属性 `pns` 的代码
147: cc.addField("public static String[] pns;"); // property name array.
148: // 添加静态属性 `pts` 的代码
149: cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
150: // 添加静态属性 `pts` 的代码
151: cc.addField("public static String[] mns;"); // all method name array.
152: // 添加静态属性 `dmns` 的代码
153: cc.addField("public static String[] dmns;"); // declared method name array.
154: // 添加静态属性 `mts` 的代码。每个方法的参数数组。
155: for (int i = 0, len = ms.size(); i < len; i++)
156: cc.addField("public static Class[] mts" + i + ";");
157:
158: // ======= 添加抽象方法的实现,到 `cc` 中
159: // 添加 `#getPropertyNames()` 的代码到 `cc`
160: cc.addMethod("public String[] getPropertyNames(){ return pns; }");
161: // 添加 `#hasProperty(n)` 的代码到 `cc`
162: cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
163: // 添加 `#getPropertyType(n)` 的代码到 `cc`
164: cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
165: // 添加 `#getMethodNames()` 的代码到 `cc`
166: cc.addMethod("public String[] getMethodNames(){ return mns; }");
167: // 添加 `#getDeclaredMethodNames()` 的代码到 `cc`
168: cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
169: // 添加 `#setPropertyValue(o, n, v)` 的代码到 `cc`
170: cc.addMethod(c1.toString());
171: // 添加 `#getPropertyValue(o, n)` 的代码到 `cc`
172: cc.addMethod(c2.toString());
173: // 添加 `#invokeMethod(o, n, p, v)` 的代码到 `cc`
174: cc.addMethod(c3.toString());
175:
176: try {
177: // 生成类
178: Class<?> wc = cc.toClass();
179: // 反射,设置静态变量的值
180: // setup static field.
181: wc.getField("pts").set(null, pts);
182: wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
183: wc.getField("mns").set(null, mns.toArray(new String[0]));
184: wc.getField("dmns").set(null, dmns.toArray(new String[0]));
185: int ix = 0;
186: for (Method m : ms.values())
187: wc.getField("mts" + ix++).set(null, m.getParameterTypes());
188: // 创建对象
189: return (Wrapper) wc.newInstance();
190: } catch (RuntimeException e) {
191: throw e;
192: } catch (Throwable e) {
193: throw new RuntimeException(e.getMessage(), e);
194: } finally {
195: // 释放资源
196: cc.release();
197: ms.clear();
198: mns.clear();
199: dmns.clear();
200: }
201: }
  • 上文生成的 Wrapper1 的代码,对应的 DempServiceImpl 的代码如下:

     1: public class DemoServiceImpl implements DemoService {
    2:
    3: /**
    4: * 测试属性,{@link com.alibaba.dubbo.common.bytecode.Wrapper}
    5: */
    6: public String test01;
    7:
    8: private DemoDAO demoDAO;
    9:
    10: public String sayHello(String name) {
    11: System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
    12: return "Hello " + name + ", response form provider: " + RpcContext.getContext().getLocalAddress();
    13: }
    14:
    15: @Override
    16: public void bye(Object o) {
    17: System.out.println(JSON.toJSONString(o));
    18: System.out.println(o.getClass());
    19: }
    20:
    21: public void setDemoDAO(DemoDAO demoDAO) {
    22: this.demoDAO = demoDAO;
    23: }
    24:
    25: }
    • 下面,我们的解析,会结合这个类一起讲。
    • ========== 生成代码 ==========
  • 第 11 至 16 行:创建方法的开头的代码:
    • #setPropertyValue(o, n, v) 的【Wrapper1 第 45 至 46 行】
    • #getPropertyValue(o, n) 的【Wrapper1 第 69 至 70 行】
    • #invokeMethod(o, n, p, v) 的【Wrapper1 第 86 至 88 行】
  • 第 19 至 21 行:设置方法的被调用对象的类型转换的代码:
    • #setPropertyValue(o, n, v) 的【Wrapper1 第 47 至 55 行】
      • #getPropertyValue(o, n) 的【Wrapper1 第 71 至 79 行】
      • #invokeMethod(o, n, p, v) 的【Wrapper1 第 89 至 97 行】
  • 第 23 至 30 行:声明 pts ms mn dmns 变量。🙂 每个变量的用途,已经添加到代码的注释上。
  • 第 32 至 44 行:循环 public 属性,添加每个属性的设置和获得分别代码:
    • 【DemoServiceImpl 第 6 行】
    • #setPropertyValue(o, n, v) 的【Wrapper1 第 56 至 60 行】
    • #getPropertyValue(o, n) 的【Wrapper1 第 80 至 62 行】
  • 第 46 至 106 行:设置方法 #invokeMethod(o, n, p, v) 的调用代码:
    • 【DemoServiceImpl 第 10 至 23 行】
    • 【Wrapper1 第 98 至 119 行】
  • 第 108 至 131 行:循环 setting / getting 属性,添加每个属性的设置和获得分别代码:
    • #setPropertyValue(o, n, v)
      • 【DemoServiceImpl 第 21 至 23 行】【DemoServiceImpl 第 8 行】
      • 【Wrapper1 第 61 至 62 行】
    • 🙂 #getPropertyValue(o, n) 没举例子,胖友自己看代码脑补。
  • ========== 生成类 ==========
  • 第 138 行:创建 ClassGenerator 对象。
  • 第 140 行:设置类名。
  • 第 142 行:设置父类为 Wrapper.class
  • 第 145 行:添加构造方法,参数为空
  • 第 146 至 156 行:添加静态属性 pns pts mns dmns mts
  • 第 158 至 174 行:添加抽象方法的实现。
  • 第 178 行:生成类。
  • ========== 创建对象 ==========
  • 第 179 至 187 行:反射,设置静态属性的值。
  • 第 189 行:创建 Wrapper 对象。
  • ========== 释放 ==========
  • 第 195 至 199 行:释放资源。

666. 彩蛋

知识星球

趁着我球结婚的日子,写完了小文一篇。

祝福我球。

感慨我们离张牙舞爪的中二少年越来越远,身旁站着妻子或未婚妻,手上抱着一脸懵逼的孩子。

总访客数 && 总访问量