动态代理(一)之Javassist
本文基于 Dubbo 2.6.1 版本,望知悉。
1. 概述
本文分享 Dubbo 动态代理的实现。
在 《Dubbo 用户指南 —— schema 配置参考手册》 中,我们可以看到 和 标签中,可以通过 “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 代码的示例:
```plain text plain 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: }
1
2
3
4
5
6
7
8
---
```plain text
- <font style="color:rgb(51, 51, 51);">该类通过 </font><font style="color:rgb(51, 51, 51);">dubbo-common</font><font style="color:rgb(51, 51, 51);"> 模块的 </font><font style="color:rgb(51, 51, 51);">bytecode</font><font style="color:rgb(51, 51, 51);"> 模块的 </font>**<font style="color:rgb(51, 51, 51);">Proxy</font>**<font style="color:rgb(51, 51, 51);"> 类,</font>**<font style="color:rgb(51, 51, 51);">自动生成</font>**<font style="color:rgb(51, 51, 51);">,使用 Javassist 技术。</font>
- <font style="color:rgb(51, 51, 51);">生成的 </font>**<font style="color:rgb(51, 51, 51);">proxy</font>**<font style="color:rgb(51, 51, 51);"> 类会</font>**<font style="color:rgb(51, 51, 51);">实现</font>**<font style="color:rgb(51, 51, 51);">我们定义的 Service 接口( 例如,此处是 DemoService )。</font>
- <font style="color:rgb(51, 51, 51);">#bye(Object)</font><font style="color:rgb(51, 51, 51);"> 和 </font><font style="color:rgb(51, 51, 51);">#sayHello(Object)</font><font style="color:rgb(51, 51, 51);"> 方法,是我们定义在 DemoService 的</font>**<font style="color:rgb(51, 51, 51);">接口方法</font>**<font style="color:rgb(51, 51, 51);">,在生成的 </font>**<font style="color:rgb(51, 51, 51);">proxy</font>**<font style="color:rgb(51, 51, 51);"> 类中,实现这些定义在接口中的方法,收拢统一调用 </font><font style="color:rgb(51, 51, 51);">java.lang.reflect.InvocationHandler#invoke(proxy, method, args)</font><font style="color:rgb(51, 51, 51);"> 方法。通过这样的方式,可以调用到最终的 </font><font style="color:rgb(51, 51, 51);">Invoker#invoke(Invocation)</font><font style="color:rgb(51, 51, 51);"> 方法,实现 RPC 调用。</font>
- <font style="color:rgb(51, 51, 51);">注意,此处我们一直用的 </font>**<font style="color:rgb(51, 51, 51);">proxy</font>**<font style="color:rgb(51, 51, 51);"> 一直是小写的,这是为什么呢?请见下文大写的 </font>**<font style="color:rgb(51, 51, 51);">Proxy</font>**<font style="color:rgb(51, 51, 51);"> 类。</font>
- 在 Provider 中,XXXProtocol 会获得被调用的 Exporter 对象,从而获得到 Invoker 对象。但是呢,Invoker 对象实际和 Service 实现对象,是无法直接调用,需要有中间的一层 Wrapper 来代理分发 到 Service 对应的方法。下面我们来看一个生成的 Wrapper 代码的示例:
```plain text plain 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: }
1
2
3
4
5
6
7
---
```plain text
- <font style="color:rgb(51, 51, 51);">该类通过 </font><font style="color:rgb(51, 51, 51);">dubbo-common</font><font style="color:rgb(51, 51, 51);"> 模块的 </font><font style="color:rgb(51, 51, 51);">bytecode</font><font style="color:rgb(51, 51, 51);"> 模块的 Wrapper 类,</font>**<font style="color:rgb(51, 51, 51);">自动生成</font>**<font style="color:rgb(51, 51, 51);">,使用 Javassist 技术。</font>
- <font style="color:rgb(51, 51, 51);">不同于生成的 </font>**<font style="color:rgb(51, 51, 51);">proxy</font>**<font style="color:rgb(51, 51, 51);">类,不实现 Service 接口类,而是在 </font><font style="color:rgb(51, 51, 51);">#invokeMethod(paramObject, paramString, paramArrayOfClass, paramArrayOfObject)</font><font style="color:rgb(51, 51, 51);"> 方法,提供给 </font><font style="color:rgb(51, 51, 51);">Invoker#invoke(invocation)</font><font style="color:rgb(51, 51, 51);"> 中调用,统一分发请求到 Service 对应的方法。从职能上来看,有一点像硬编码的 Controller 。</font>
- <font style="color:rgb(51, 51, 51);">一个生成的 </font>**<font style="color:rgb(51, 51, 51);">Wrapper</font>**<font style="color:rgb(51, 51, 51);">类,只对应一个 Service ,从第 75 行的代码,我们也可以看出。</font>
4. ProxyFactory
com.alibaba.dubbo.rpc.ProxyFactory ,代理工厂接口。
在 《精尽 Dubbo 源码分析 —— 核心流程一览》 的 「4.5 ProxyFactory」,已经分享,胖友点击查看。
ProxyFactory 子类
4.1 AbstractProxyFactory
com.alibaba.dubbo.rpc.proxy.AbstractProxyFactory ,实现 ProxyFactory 接口,代理工厂抽象类。代码如下:
```plain text plain 1: public abstract class AbstractProxyFactory implements ProxyFactory { 2: 3: public
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
---
- 可以看到,该抽象类,主要是实现了
#getProxy(invoker)
方法,获得需要生成代理的接口们。
- 第 5 至 17 行: TODO 8022 芋艿
- 第 18 至 21 行:在原有 Invoker 对应**关联**[《Dubbo 用户指南 —— 回声测试》](http://dubbo.apache.org/zh-cn/docs/user/demos/echo-service.html)
的 Service 接口之上,增加 EchoService 接口。
FROM
回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,能够测试整个调用是否通畅,可用于监控。
所有服务自动实现 EchoService 接口,只需将任意服务引用强制转型为 EchoService,即可使用。
- 第 22 行:调用 **抽象**
#getProxy(invoker, types)
方法,获得 Proxy 对象。
## 4.2 StubProxyFactoryWrapper
[com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper](https://github.com/YunaiV/dubbo/blob/afb312f7dce997f5f90ba686345f4354e786534d/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java) ,实现 ProxyFactory 接口,Stub 代理工厂 Wrapper 实现类,基于 Dubbo SPI Wrapper 机制加载。
该类,不在本文的范畴内,感兴趣的胖友可以先看下 [《Dubbo 用户指南 —— 本地存根》](http://dubbo.apache.org/zh-cn/docs/user/demos/local-stub.html) 。后续,我们单独开文章分享。
## 4.3 JavassistProxyFactory
com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory ,实现 AbstractProxyFactory 抽象类,基于 Javassist 代理工厂实现类。代码如下:
```plain text
plain 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 Proxy#getProxy(interface) 方法,获得 对象。
- 第 5 行:调用 proxy Proxy#newInstance(InvocationHandler) 方法,获得 对象。其中传入的参数是 InvokerInvocationHandler 类,通过这样的方式,让 proxy 和真正的逻辑代码解耦。
- Proxy 和 proxy ,在 「7.3 Proxy」 中,详细解析。
- InvokerInvocationHandler ,在 「5. InvokerInvocationHandler」 中,详细解析。
- #getInvoker(proxy, type, url) 方法
- 第 11 行:调用 Wrapper Wrapper#getWrapper(Class<?>) 方法,获得 对象。
- Wrapper ,在 「7.4 Wrapper」 中,详细解析。
- 第 12 至 19 行:创建 AbstractProxyInvoker 对象,实现 #doInvoke(…) 方法。在该方法中,调用 Wrapper#invokeMethod(…) 方法,从而调用 Service 的方法。
- AbstractProxyInvoker ,在 「6. AbstractProxyInvoker」 中,详细解析。
- 第 11 行:调用 Wrapper Wrapper#getWrapper(Class<?>) 方法,获得 对象。
5. InvokerInvocationHandler
com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler ,实现 java.lang.reflect.InvocationHandler 接口,代码如下:
```plain text plain 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: }
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
---
- 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()
方法,回放调用结果。代码如下:
```plain text
plain // RpcResult.java public Object recreate() throws Throwable { // 有异常,抛出异常 if (exception != null) { throw exception; } // 无异常,返回结果 return result; }
```plain text * x
1
2
3
4
5
6
7
8
9
10
11
通过 InvokerInvocationHandler ,可以实现 Proxy 和真正的逻辑解耦。
# 6. AbstractProxyInvoker
com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker ,实现 Invoker 接口,**代理** Invoker 对象的抽象类。
## 6.1 属性
```plain text
plain /** * 代理的对象,一般是 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
```plain text plain 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: }
1
2
3
4
5
6
7
8
9
10
11
---
- 第 3 行:调用 **抽象**
#doInvoke(..)
方法,执行调用,返回调用结果。
#doInvoke(…)
方法,代码如下:
```plain text
plain /** * 执行调用 * * @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 代码的示例,代码如下:
```plain text plain public class Proxy0 extends Proxy implements ClassGenerator.DC { public Object newInstance(InvocationHandler paramInvocationHandler) { return new proxy0(paramInvocationHandler); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
- **生成的Proxy生成的proxy**
实现 Proxy 抽象类,是创建
的工厂(一一对应)。例如,Proxy0 创建 proxy0 对象。
- #newInstance(InvocationHandler)**生成的proxy**
方法,创建
的方法。
## 7.4 Wrapper
[com.alibaba.dubbo.common.bytecode.Wrapper](http://svip.iocoder.cn/Dubbo/proxy-javassist/TODO) ,Wrapper 抽象类,用于**创建某个对象的方法调用**的包装器,以避免**反射**调用,提高性能。即:
```plain text
plain // 反射 Method#invoke(Object instance, Object[] args) // 优化成===> // Wrapper Wrapper#invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args)
- 为什么会提高性能呢?看到上文的 Wrapper 代理的示例,相信胖友已经明白。
7.4.1 抽象方法
在自动生成 Wrapper 类时,需要实现如下抽象方法:
```plain text plain 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;
1
2
3
4
5
6
7
8
9
---
### 7.4.2 getWrapper
#getWrapper(c) 方法,根据指定类,获得 Wrapper 对象。代码如下:
```plain text
plain 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 代码如下:
```plain text plain /** * Wrapper 对象缓存 * key :Wrapper 类。 * value :Proxy 对象 */ private static final Map<Class<?>, Wrapper> WRAPPER_MAP = new ConcurrentHashMap<Class<?>, Wrapper>(); //class wrapper map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
- 第 13 至 16 行:调用
#makeWrapper(Class<?>)
方法,创建 Wrapper 对象,并添加到缓存。
### 7.4.3 makeWrapper
#makeWrapper(Class<?>) 方法,创建 Wrapper 对象。代码如下:
旁白君:实现上,和 Proxy 差不过的,只生成**一个** Wrapper 类。
```plain text
plain 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 的代码如下:
```plain text plain 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: }
1
2
3
4
5
6
---
```plain text
- <font style="color:rgb(51, 51, 51);">下面,我们的解析,会结合这个类一起讲。</font>
- <font style="color:rgb(51, 51, 51);">========== 生成代码 ==========</font>
- 第 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 行】
- #setPropertyValue(o, n, v) 的【Wrapper1 第 47 至 55 行】
- 第 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) 没举例子,胖友自己看代码脑补。
- #setPropertyValue(o, n, v)
- ========== 生成类 ==========
- 第 138 行:创建 ClassGenerator 对象。
- 第 140 行:设置类名。
- 第 142 行:设置父类为 Wrapper.class
- 第 145 行:添加构造方法,参数为空
- 第 146 至 156 行:添加静态属性 pns pts mns dmns mts 。
- 第 158 至 174 行:添加抽象方法 的实现。
- 第 178 行:生成类。
- ========== 创建对象 ==========
- 第 179 至 187 行:反射,设置静态属性 的值。
- 第 189 行:创建 Wrapper 对象。
- ========== 释放 ==========
- 第 195 至 199 行:释放资源。
666. 彩蛋
知识星球
趁着我球结婚的日子,写完了小文一篇。
祝福我球。
感慨我们离张牙舞爪的中二少年越来越远,身旁站着妻子或未婚妻,手上抱着一脸懵逼的孩子。


