动态代理(三)之本地存根Stub
本文基于 Dubbo 2.6.1 版本,望知悉。
1. 概述
本文接 《精尽 Dubbo 源码分析 —— 动态代理(二)之 JDK》 一文,分享使用 Dubbo 本地存根( Stub )的特性。 当然,从标题我们就可以看出,实现的原理是基于动态代理的机制。
在 《Dubbo 用户指南 —— 本地存根》 中,已经非常详尽的分享了本地存根的概念和使用,本文就不重复介绍啦。 文档有一点点小小的错误,在 Spring 配置文件的配置方式应该是如下:
```plain text plain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
- 是服务引用
,而不是服务暴露
# 2. StubProxyFactoryWrapper
[com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper](http://svip.iocoder.cn/Dubbo/proxy-local-stub/TODO) ,实现 ProxyFactory 接口,存根代理工厂**包装器**实现类。
## 2.1 构造方法
```plain text
plain /** * ProxyFactory$Adaptive 对象 */ private final ProxyFactory proxyFactory; /** * Protocol$Adaptive 对象 */ private Protocol protocol; public StubProxyFactoryWrapper(ProxyFactory proxyFactory) { this.proxyFactory = proxyFactory; } public void setProtocol(Protocol protocol) { this.protocol = protocol; }
- proxyFactory 属性,ProxyFactory$Adaptive 对象。StubProxyFactoryWrapper 基于 Dubbo SPI Wrapper 机制,所以使用 ProxyFactory 创建代理的流程,实际变成如下:
流程 - protocol 属性,Protocol$Adaptive 对象。
2.2 getProxy
```plain text plain 1: @Override 2: @SuppressWarnings({“unchecked”, “rawtypes”}) 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
29
30
31
32
33
34
35
36
37
38
39
40
---
- 【**第一步**[《精尽 Dubbo 源码解析 —— 动态代理》](http://svip.iocoder.cn/Dubbo/proxy-local-stub/#)
】第 5 行:调用
proxyFactory#getProxy(invoker)
方法,获得 Service Proxy 对象。这个过程,就是我们在
前两篇看到的内容。
- 第 6 行:若是泛化引用,不支持使用本地存根。
- 第 8 至 18 行:获得 **注意等价**
stub
配置项。
,
local
配置项,和
stub
配置项是
的,目前使用
stub
而不使用
local
。
- 第 20 至 24 行:调用
ReflectUtils#forName(stub)
方法,加载 Stub 类。
- 【**第二步使用带 Service Proxy 对象作为参数的构造方法包装在内部**
】第 26 至 28 行:创建 Stub 对象,
。例如,
public DemoServiceStub(DemoService demoService)
。通过这样的方式,我们的 Stub 对象,就将 Proxy Service 对象,
,可以实现各种 OOXX 啦。
- 第 30 至 41 行:【TODO 8033】参数回调。先无视。
- 第 51 行:返回最终的
proxy
。
## 2.3 getInvoker
```plain text
plain @Override public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException { return proxyFactory.getInvoker(proxy, type, url); }
- 服务实现的 Service ,不支持 Stub 存根。所以,虽然 有 stub 配置项,但是实际是没有效果的。
3. 校验 Stub 配置
在 #checkStubAndMock(interfaceClass) 方法中,有校验 stub 配置项的代码,如下:
plain text plain // `local` 配置项的校验,和 `stub` 一样。 if (ConfigUtils.isNotEmpty(local)) { Class<?> localClass = ConfigUtils.isDefault(local) ? ReflectUtils.forName(interfaceClass.getName() + "Local") : ReflectUtils.forName(local); if (!interfaceClass.isAssignableFrom(localClass)) { throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceClass.getName()); } try { ReflectUtils.findConstructor(localClass, interfaceClass); } catch (NoSuchMethodException e) { throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")\" in local implementation class " + localClass.getName()); } } // `stub` 配置项的校验 if (ConfigUtils.isNotEmpty(stub)) { // `stub = true` 的情况,使用接口 + `Stub` 字符串。 Class<?> localClass = ConfigUtils.isDefault(stub) ? ReflectUtils.forName(interfaceClass.getName() + "Stub") : ReflectUtils.forName(stub); // Stub 类,必须实现服务接口 if (!interfaceClass.isAssignableFrom(localClass)) { throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceClass.getName()); } // Stub 类,必须带有服务接口的构造方法 try { ReflectUtils.findConstructor(localClass, interfaceClass); } catch (NoSuchMethodException e) { throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")\" in local implementation class " + localClass.getName()); } }
666. 彩蛋
知识星球
小文一篇。
