2.2.1 Invoker 创建过程

在 Dubbo 中,Invoker 是一个非常重要的模型。在服务提供端,以及服务引用端均会出现 Invoker。Dubbo 官方文档中对 Invoker 进行了说明,这里引用一下。

Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。

既然 Invoker 如此重要,那么我们很有必要搞清楚 Invoker 的用途。Invoker 是由 ProxyFactory 创建而来,Dubbo 默认的 ProxyFactory 实现类是 JavassistProxyFactory。下面我们到 JavassistProxyFactory 代码中,探索 Invoker 的创建过程。如下:

  1. public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
  2. // 为目标类创建 Wrapper
  3. final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
  4. // 创建匿名 Invoker 类对象,并实现 doInvoke 方法。
  5. return new AbstractProxyInvoker<T>(proxy, type, url) {
  6. @Override
  7. protected Object doInvoke(T proxy, String methodName,
  8. Class<?>[] parameterTypes,
  9. Object[] arguments) throws Throwable {
  10. // 调用 Wrapper 的 invokeMethod 方法,invokeMethod 最终会调用目标方法
  11. return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
  12. }
  13. };
  14. }

如上,JavassistProxyFactory 创建了一个继承自 AbstractProxyInvoker 类的匿名对象,并覆写了抽象方法 doInvoke。覆写后的 doInvoke 逻辑比较简单,仅是将调用请求转发给了 Wrapper 类的 invokeMethod 方法。Wrapper 用于“包裹”目标类,Wrapper 是一个抽象类,仅可通过 getWrapper(Class) 方法创建子类。在创建 Wrapper 子类的过程中,子类代码生成逻辑会对 getWrapper 方法传入的 Class 对象进行解析,拿到诸如类方法,类成员变量等信息。以及生成 invokeMethod 方法代码和其他一些方法代码。代码生成完毕后,通过 Javassist 生成 Class 对象,最后再通过反射创建 Wrapper 实例。相关的代码如下:

  1. public static Wrapper getWrapper(Class<?> c) {
  2. while (ClassGenerator.isDynamicClass(c))
  3. c = c.getSuperclass();
  4. if (c == Object.class)
  5. return OBJECT_WRAPPER;
  6. // 从缓存中获取 Wrapper 实例
  7. Wrapper ret = WRAPPER_MAP.get(c);
  8. if (ret == null) {
  9. // 缓存未命中,创建 Wrapper
  10. ret = makeWrapper(c);
  11. // 写入缓存
  12. WRAPPER_MAP.put(c, ret);
  13. }
  14. return ret;
  15. }

getWrapper 方法仅包含一些缓存操作逻辑,不难理解。下面我们看一下 makeWrapper 方法。

  1. private static Wrapper makeWrapper(Class<?> c) {
  2. // 检测 c 是否为基本类型,若是则抛出异常
  3. if (c.isPrimitive())
  4. throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
  5. String name = c.getName();
  6. ClassLoader cl = ClassHelper.getClassLoader(c);
  7. // c1 用于存储 setPropertyValue 方法代码
  8. StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
  9. // c2 用于存储 getPropertyValue 方法代码
  10. StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
  11. // c3 用于存储 invokeMethod 方法代码
  12. StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
  13. // 生成类型转换代码及异常捕捉代码,比如:
  14. // DemoService w; try { w = ((DemoServcie) $1); }}catch(Throwable e){ throw new IllegalArgumentException(e); }
  15. c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
  16. c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
  17. c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
  18. // pts 用于存储成员变量名和类型
  19. Map<String, Class<?>> pts = new HashMap<String, Class<?>>();
  20. // ms 用于存储方法描述信息(可理解为方法签名)及 Method 实例
  21. Map<String, Method> ms = new LinkedHashMap<String, Method>();
  22. // mns 为方法名列表
  23. List<String> mns = new ArrayList<String>();
  24. // dmns 用于存储“定义在当前类中的方法”的名称
  25. List<String> dmns = new ArrayList<String>();
  26. // --------------------------------✨ 分割线1 ✨-------------------------------------
  27. // 获取 public 访问级别的字段,并为所有字段生成条件判断语句
  28. for (Field f : c.getFields()) {
  29. String fn = f.getName();
  30. Class<?> ft = f.getType();
  31. if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()))
  32. // 忽略关键字 static 或 transient 修饰的变量
  33. continue;
  34. // 生成条件判断及赋值语句,比如:
  35. // if( $2.equals("name") ) { w.name = (java.lang.String) $3; return;}
  36. // if( $2.equals("age") ) { w.age = ((Number) $3).intValue(); return;}
  37. c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
  38. // 生成条件判断及返回语句,比如:
  39. // if( $2.equals("name") ) { return ($w)w.name; }
  40. c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
  41. // 存储 <字段名, 字段类型> 键值对到 pts 中
  42. pts.put(fn, ft);
  43. }
  44. // --------------------------------✨ 分割线2 ✨-------------------------------------
  45. Method[] methods = c.getMethods();
  46. // 检测 c 中是否包含在当前类中声明的方法
  47. boolean hasMethod = hasMethods(methods);
  48. if (hasMethod) {
  49. c3.append(" try{");
  50. }
  51. for (Method m : methods) {
  52. if (m.getDeclaringClass() == Object.class)
  53. // 忽略 Object 中定义的方法
  54. continue;
  55. String mn = m.getName();
  56. // 生成方法名判断语句,比如:
  57. // if ( "sayHello".equals( $2 )
  58. c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
  59. int len = m.getParameterTypes().length;
  60. // 生成“运行时传入的参数数量与方法参数列表长度”判断语句,比如:
  61. // && $3.length == 2
  62. c3.append(" && ").append(" $3.length == ").append(len);
  63. boolean override = false;
  64. for (Method m2 : methods) {
  65. // 检测方法是否存在重载情况,条件为:方法对象不同 && 方法名相同
  66. if (m != m2 && m.getName().equals(m2.getName())) {
  67. override = true;
  68. break;
  69. }
  70. }
  71. // 对重载方法进行处理,考虑下面的方法:
  72. // 1. void sayHello(Integer, String)
  73. // 2. void sayHello(Integer, Integer)
  74. // 方法名相同,参数列表长度也相同,因此不能仅通过这两项判断两个方法是否相等。
  75. // 需要进一步判断方法的参数类型
  76. if (override) {
  77. if (len > 0) {
  78. for (int l = 0; l < len; l++) {
  79. // 生成参数类型进行检测代码,比如:
  80. // && $3[0].getName().equals("java.lang.Integer")
  81. // && $3[1].getName().equals("java.lang.String")
  82. c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
  83. .append(m.getParameterTypes()[l].getName()).append("\")");
  84. }
  85. }
  86. }
  87. // 添加 ) {,完成方法判断语句,此时生成的代码可能如下(已格式化):
  88. // if ("sayHello".equals($2)
  89. // && $3.length == 2
  90. // && $3[0].getName().equals("java.lang.Integer")
  91. // && $3[1].getName().equals("java.lang.String")) {
  92. c3.append(" ) { ");
  93. // 根据返回值类型生成目标方法调用语句
  94. if (m.getReturnType() == Void.TYPE)
  95. // w.sayHello((java.lang.Integer)$4[0], (java.lang.String)$4[1]); return null;
  96. c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
  97. else
  98. // return w.sayHello((java.lang.Integer)$4[0], (java.lang.String)$4[1]);
  99. c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");
  100. // 添加 }, 生成的代码形如(已格式化):
  101. // if ("sayHello".equals($2)
  102. // && $3.length == 2
  103. // && $3[0].getName().equals("java.lang.Integer")
  104. // && $3[1].getName().equals("java.lang.String")) {
  105. //
  106. // w.sayHello((java.lang.Integer)$4[0], (java.lang.String)$4[1]);
  107. // return null;
  108. // }
  109. c3.append(" }");
  110. // 添加方法名到 mns 集合中
  111. mns.add(mn);
  112. // 检测当前方法是否在 c 中被声明的
  113. if (m.getDeclaringClass() == c)
  114. // 若是,则将当前方法名添加到 dmns 中
  115. dmns.add(mn);
  116. ms.put(ReflectUtils.getDesc(m), m);
  117. }
  118. if (hasMethod) {
  119. // 添加异常捕捉语句
  120. c3.append(" } catch(Throwable e) { ");
  121. c3.append(" throw new java.lang.reflect.InvocationTargetException(e); ");
  122. c3.append(" }");
  123. }
  124. // 添加 NoSuchMethodException 异常抛出代码
  125. c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");
  126. // --------------------------------✨ 分割线3 ✨-------------------------------------
  127. Matcher matcher;
  128. // 处理 get/set 方法
  129. for (Map.Entry<String, Method> entry : ms.entrySet()) {
  130. String md = entry.getKey();
  131. Method method = (Method) entry.getValue();
  132. // 匹配以 get 开头的方法
  133. if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
  134. // 获取属性名
  135. String pn = propertyName(matcher.group(1));
  136. // 生成属性判断以及返回语句,示例如下:
  137. // if( $2.equals("name") ) { return ($w).w.getName(); }
  138. c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
  139. pts.put(pn, method.getReturnType());
  140. // 匹配以 is/has/can 开头的方法
  141. } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
  142. String pn = propertyName(matcher.group(1));
  143. // 生成属性判断以及返回语句,示例如下:
  144. // if( $2.equals("dream") ) { return ($w).w.hasDream(); }
  145. c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
  146. pts.put(pn, method.getReturnType());
  147. // 匹配以 set 开头的方法
  148. } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
  149. Class<?> pt = method.getParameterTypes()[0];
  150. String pn = propertyName(matcher.group(1));
  151. // 生成属性判断以及 setter 调用语句,示例如下:
  152. // if( $2.equals("name") ) { w.setName((java.lang.String)$3); return; }
  153. c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");
  154. pts.put(pn, pt);
  155. }
  156. }
  157. // 添加 NoSuchPropertyException 异常抛出代码
  158. c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
  159. c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
  160. // --------------------------------✨ 分割线4 ✨-------------------------------------
  161. long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
  162. // 创建类生成器
  163. ClassGenerator cc = ClassGenerator.newInstance(cl);
  164. // 设置类名及超类
  165. cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
  166. cc.setSuperClass(Wrapper.class);
  167. // 添加默认构造方法
  168. cc.addDefaultConstructor();
  169. // 添加字段
  170. cc.addField("public static String[] pns;");
  171. cc.addField("public static " + Map.class.getName() + " pts;");
  172. cc.addField("public static String[] mns;");
  173. cc.addField("public static String[] dmns;");
  174. for (int i = 0, len = ms.size(); i < len; i++)
  175. cc.addField("public static Class[] mts" + i + ";");
  176. // 添加方法代码
  177. cc.addMethod("public String[] getPropertyNames(){ return pns; }");
  178. cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
  179. cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
  180. cc.addMethod("public String[] getMethodNames(){ return mns; }");
  181. cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
  182. cc.addMethod(c1.toString());
  183. cc.addMethod(c2.toString());
  184. cc.addMethod(c3.toString());
  185. try {
  186. // 生成类
  187. Class<?> wc = cc.toClass();
  188. // 设置字段值
  189. wc.getField("pts").set(null, pts);
  190. wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
  191. wc.getField("mns").set(null, mns.toArray(new String[0]));
  192. wc.getField("dmns").set(null, dmns.toArray(new String[0]));
  193. int ix = 0;
  194. for (Method m : ms.values())
  195. wc.getField("mts" + ix++).set(null, m.getParameterTypes());
  196. // 创建 Wrapper 实例
  197. return (Wrapper) wc.newInstance();
  198. } catch (RuntimeException e) {
  199. throw e;
  200. } catch (Throwable e) {
  201. throw new RuntimeException(e.getMessage(), e);
  202. } finally {
  203. cc.release();
  204. ms.clear();
  205. mns.clear();
  206. dmns.clear();
  207. }
  208. }

上面代码很长,大家耐心看一下。我们在上面代码中做了大量的注释,并按功能对代码进行了分块,以帮助大家理解代码逻辑。下面对这段代码进行讲解。首先我们把目光移到分割线1之上的代码,这段代码主要用于进行一些初始化操作。比如创建 c1、c2、c3 以及 pts、ms、mns 等变量,以及向 c1、c2、c3 中添加方法定义和类型转换代码。接下来是分割线1到分割线2之间的代码,这段代码用于为 public 级别的字段生成条件判断取值与赋值代码。这段代码不是很难看懂,就不多说了。继续向下看,分割线2和分隔线3之间的代码用于为定义在当前类中的方法生成判断语句,和方法调用语句。因为需要对方法重载进行校验,因此到这这段代码看起来有点复杂。不过耐心看一下,也不是很难理解。接下来是分割线3和分隔线4之间的代码,这段代码用于处理 getter、setter 以及以 is/has/can 开头的方法。处理方式是通过正则表达式获取方法类型(get/set/is/…),以及属性名。之后为属性名生成判断语句,然后为方法生成调用语句。最后我们再来看一下分隔线4以下的代码,这段代码通过 ClassGenerator 为刚刚生成的代码构建 Class 类,并通过反射创建对象。ClassGenerator 是 Dubbo 自己封装的,该类的核心是 toClass() 的重载方法 toClass(ClassLoader, ProtectionDomain),该方法通过 javassist 构建 Class。这里就不分析 toClass 方法了,大家请自行分析。

阅读 Wrapper 类代码需要对 javassist 框架有所了解。关于 javassist,大家如果不熟悉,请自行查阅资料,本节不打算介绍 javassist 相关内容。

好了,关于 Wrapper 类生成过程就分析到这。如果大家看的不是很明白,可以单独为 Wrapper 创建单元测试,然后单步调试。并将生成的代码拷贝出来,格式化后再进行观察和理解。