<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 应用名,通常与 artifactId 相同即可 -->
<dubbo:application name="demo-consumer"/>
<!-- 注册中心 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 生成远端服务的代理对象, 之后可以向调用本地服务一样调用远端服务 -->
<dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService"/>
</beans>
服务消费者创建服务代理
// demoService 是代理对象,代理对象是 DemoService 接口的实现类
DemoService demoService = (DemoService) context.getBean("demoService");
一、服务消费者创建服务代理简图
Alt pic
总体流程:(默认配置情况下)
- 首先 ReferenceConfig 类的 init 方法调用
Protocol#refer
方法生成 Invoker 实例(如上图中的红色部分),这是服务消费的关键。- 然后使用 JavassistProxyFactory#getProxy 生成接口(DemoService)的代理对象 ref
image.png
- 服务引用第一步,有注册中心的情况下(最常用)会调用
RegistryProtocol#refer(Class<T> type, URL url)
,RegistryProtocol 实际上是其他具体 Protocol(eg. DubboProtocol)的 AOP 类,在refer(...)
中:
- 获取注册中心
- 创建 RegistryDirectory(AOP)
- 首先会获取注册中心 Registry,然后进行服务注册;(AOP)
- 订阅providers、configurators、routers
4.1. 做第一次服务发现,获取到 provider 节点(provider 以 URL 进行表示)后;(AOP)
4.2.之后使用具体的 DubboProtocol 将这些表示 provider 的 URL 转化为 DubboInvoker,并且为每一个 provider 创建 nettyClient,与 nettyServer 进行连接
(具体的 Protocol 做的事
)
4.3、进行 DubboInvoker 的缓存(AOP),其中 RegistryDirectory#Map<String, List<Invoker<T>>> methodInvokerMap 是后续发起调用时获取 Invoker 的真正容器(重要
)
- 将directory封装成一个ClusterInvoker(MockClusterInvoker)。
public class RegistryProtocol implements Protocol {
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
...
// 1. 获取注册中心:创建ZkClient实例,连接zk
Registry registry = registryFactory.getRegistry(url);
...
// 2.
return doRefer(cluster, registry, type, url);
}
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
// 1. 创建 RegistryDirectory 实例
RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
...
// 2. 向注册中心注册服务
registry.register(registeredConsumerUrl);
// 3. 订阅providers、configurators、routers(订阅时,调用了具体的Protocol,eg. DubboProtocol 的 refer(RegistryDirectory),方法,在该方法中,创建了 nettyClient 端,并建立了长连接)
directory.subscribe(subscribeUrl.addParameter("category","providers,configurators,routers"));
// 4. 将directory封装成一个ClusterInvoker(MockClusterInvoker)
Invoker invoker = cluster.join(directory);
...
return invoker;
}
}
大致看下后续发起调用时,是怎么从 RegistryDirectory 中获取可执行的 Invoker 的。
public class RegistryDirectory<T> extends AbstractDirectory<T> implements NotifyListener {
// 以注释处的例子为例,初始化之后:{"sayHello":[A,B], "sayBye":[B], "*":[router过滤后的provider]}
private volatile Map<String, List<Invoker<T>>> methodInvokerMap;
/************************* 初始化更新 newMethodInvokerMap *************************/
// 订阅providers、configurators、routers时,执行的通知逻辑
@Override
public synchronized void notify(List<URL> urls) {
// 服务提供者URL
List<URL> invokerUrls = new ArrayList<URL>();
...
// 初始化 invokerUrls
for (URL url : urls) {
String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
...
if (Constants.PROVIDERS_CATEGORY.equals(category)) {
invokerUrls.add(url);
}
}
...
// 只针对 providers 进行调用
refreshInvoker(invokerUrls);
}
private void refreshInvoker(List<URL> invokerUrls) {
...
// Translate url list to Invoker map => 将url转换为InvokerDelegate
Map<String, Invoker<T>> newUrlInvokerMap = toInvokers(invokerUrls);
// Change method name to map Invoker Map => 构造{"sayHello":InvokerDelegate}这样的键值对
Map<String, List<Invoker<T>>> newMethodInvokerMap = toMethodInvokers(newUrlInvokerMap);
...
// 初始化实例属性 methodInvokerMap
this.methodInvokerMap = newMethodInvokerMap;
...
}
private Map<String, List<Invoker<T>>> toMethodInvokers(Map<String, Invoker<T>> invokersMap) {
Map<String, List<Invoker<T>>> newMethodInvokerMap = new HashMap<String, List<Invoker<T>>>();
...
for (Invoker<T> invoker : invokersMap.values()) {
// 1. 获取 provider 的所有方法 methods=xxx,yyy,zzz
// (同一个接口的不同 provider 的 methods 参数可能不同,例如 DemoService#sayHello() 在 providerA 中有,后续添加了 DemoService#sayBye() 之后,部署到了 providerB,
// 此时 providerA 还没部署,这一时刻,进行的服务发现根据 serviceKey 会发现 providerA 和 providerB,但是二者所拥有的方法却是不同的,那么经过如下逻辑后,
// newMethodInvokerMap={"sayHello":[A,B], "sayBye":[B]})
String parameter = invoker.getUrl().getParameter(Constants.METHODS_KEY);
String[] methods = Constants.COMMA_SPLIT_PATTERN.split(parameter);
for (String method : methods) {
...
newMethodInvokerMap.put(method, methodInvokers);
...
}
}
// newMethodInvokerMap={"sayHello":[A,B], "sayBye":[B], "*":[router过滤后的provider]}
newMethodInvokerMap.put(Constants.ANY_VALUE, newInvokersList);
...
return Collections.unmodifiableMap(newMethodInvokerMap);
}
/************************* 从 newMethodInvokerMap 中选择 Invoker *************************/
@Override
public List<Invoker<T>> doList(Invocation invocation) {
...
List<Invoker<T>> invokers = null;
Map<String, List<Invoker<T>>> localMethodInvokerMap = this.methodInvokerMap; // local reference
if (localMethodInvokerMap != null && localMethodInvokerMap.size() > 0) {
String methodName = RpcUtils.getMethodName(invocation);
...
// 1. 根据方法名进行 Invoker 的获取:从 {"sayHello":List<InvokerDelegate实例>} 中根据 methodName("sayHello")获取List<InvokerDelegate实例>
if (invokers == null) {
invokers = localMethodInvokerMap.get(methodName);
}
// 2. 根据 key=* 进行获取 List<Invoker>
if (invokers == null) {
invokers = localMethodInvokerMap.get(Constants.ANY_VALUE);
}
// 3. 遍历获取一个 List<Invoker>
if (invokers == null) {
Iterator<List<Invoker<T>>> iterator = localMethodInvokerMap.values().iterator();
if (iterator.hasNext()) {
invokers = iterator.next();
}
}
}
return invokers == null ? new ArrayList<Invoker<T>>(0) : invokers;
}
...
}
Q
: 为什么要按照方法名进行 provider 的缓存而不是直接按照 interfaceName/group/version 这样的格式?
A
: 同一个接口的不同 provider 的 methods 参数可能不同,例如 DemoService#sayHello() 在 providerA 中有,后续添加了 DemoService#sayBye() 之后,部署到了 providerB,同时将新包(包含sayBye())打包给 consumer,consumer 部署完成后,假设此时 providerA 还没部署,这一时刻,consumer 进行的服务发现根据 serviceKey 会发现 providerA 和 providerB,但是二者所拥有的方法却是不同的,那么经过如下逻辑后,newMethodInvokerMap={"sayHello":[A,B], "sayBye":[B]}
),这样后续如果执行 DemoService#sayBye() ,就会直接获取到 B。
注意
:在 2.7.x 中去掉了 newMethodInvokerMap 属性,不再使用方法名作为 key,直接存储 List<Invoker>,代码虽然简化了,但是也丢失了A
中描述的好处。
服务引用的第二步,见下文第二小节分析和 第10章 Dubbo 代理层的设计与实现
二、服务消费者创建服务代理源码梯形图
ReferenceConfig.init()
-->createProxy(Map<String, String> map)
//一 获取Invoker
-->RegistryProtocol.refer(Class<T> type, URL url)
//1 获取注册中心:创建ZkClient实例,连接zk
-->Registry registry = registryFactory.getRegistry(url)
-->AbstractRegistryFactory.getRegistry(URL url)
-->ZookeeperRegistryFactory.createRegistry(URL url)
-->new ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter)
-->ZkclientZookeeperTransporter.connect(URL url)
-->new ZkclientZookeeperClient(URL url)
-->new ZkClient(url.getBackupAddress())
-->AbstractRegistryFactory.Map<String, Registry> REGISTRIES.put("zookeeper://10.211.55.5:2181/com.alibaba.dubbo.registry.RegistryService", 上边的ZookeeperRegistry实例)
-->doRefer(Cluster cluster, Registry registry, Class<T> type, URL url)
-->new RegistryDirectory<T>(type, url)
//2 向注册中心注册服务
-->registry.register(url)
-->ZookeeperRegistry.doRegister(URL url)
-->AbstractZookeeperClient.create(String path, boolean ephemeral)
//3 订阅providers、configurators、routers
-->RegistryDirectory.subscribe(URL url)
-->ZookeeperRegistry.doSubscribe(final URL url, final NotifyListener listener)
//3.1 会获取当前节点下已经存在的子节点(第一次服务发现发生在这里),添加子节点变化监听器
-->List<String> children = zkClient.addChildListener(path, zkListener)
-->AbstractRegistry.notify(URL url, NotifyListener listener, List<URL> urls)
-->saveProperties(url)
-->RegistryDirectory.notify(List<URL> urls)
//仅仅针对的是providers
-->refreshInvoker(List<URL> invokerUrls)
-->toInvokers(List<URL> urls)
-->ProtocolFilterWrapper.refer(Class<T> type, URL url)
-->DubboProtocol.refer(Class<T> serviceType, URL url)
//3.1.1 创建ExchangeClient,对第一次服务发现providers路径下的相关url建立长连接
-->getClients(URL url)
-->getSharedClient(URL url)
-->ExchangeClient exchangeClient = initClient(url)
-->Exchangers.connect(url, requestHandler)
-->HeaderExchanger.connect(URL url, ExchangeHandler handler)
-->new DecodeHandler(new HeaderExchangeHandler(handler)))
-->Transporters.connect(URL url, ChannelHandler... handlers)
-->NettyTransporter.connect(URL url, ChannelHandler listener)
-->new NettyClient(url, listener)
-->new MultiMessageHandler(HeartbeatHandler(AllChannelHandler(handler)))
-->getChannelCodec(url)//获取Codec2,这里是DubboCountCodec实例
-->doOpen()//开启netty客户端
-->doConnect()//连接服务端,建立长连接
-->new HeaderExchangeClient(Client client, boolean needHeartbeat)//上述的NettyClient实例,needHeartbeat:true
-->startHeatbeatTimer()//启动心跳计数器
-->ReferenceCountExchangeClient(ExchangeClient client, ConcurrentMap<String, LazyConnectExchangeClient> ghostClientMap)/
-->Map<String, ReferenceCountExchangeClient> referenceClientMap.put("10.10.10.10:20880", 上边的ReferenceCountExchangeClient实例)
//3.2 创建DubboInvoker(nettyClient的持有者,真正发起netty调用的Invoker,做两件事:选择nettyClient + 处理单向/异步/同步调用模板)
-->new DubboInvoker(Class<T> serviceType, URL url, ExchangeClient[] clients, Set<Invoker<?>> invokers)
-->DubboProtocol.Set<Invoker<?>> invokers.add(上边的DubboInvoker实例)
-->ProtocolFilterWrapper.buildInvokerChain(final Invoker<T> invoker, String key, String group)
-->new InvokerDelegete(Invoker<T> invoker, URL url, URL providerUrl)
//3.3 将创建出来的Invoker缓存起来
-->newUrlInvokerMap.put("dubbo://10.10.10.10:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-consumer&check=false&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=16001®ister.ip=10.10.10.10&remote.timestamp=1510127991625&side=consumer×tamp=1510128022123", 上边的InvokerDelegate实例)
-->toMethodInvokers(newUrlInvokerMap)
-->Map<String, List<Invoker<T>>> newMethodInvokerMap:{sayHello=[InvokerDelegete实例], *=[InvokerDelegete实例]}
//4 将directory封装成一个ClusterInvoker(MockClusterInvoker)
-->cluster.join(directory)
-->Cluster$Adaptive.join(directory)
-->ExtensionLoader.getExtensionLoader(Cluster.class).getExtension("failover")//MockClusterWrapper包装FailoverCluster
-->MockClusterWrapper.join(Directory<T> directory)
-->FailoverCluster.join(Directory<T> directory)
-->new FailoverClusterInvoker<T>(directory)
-->MockClusterInvoker(Directory<T> directory, Invoker<T> invoker)//invoker:上边的FailoverClusterInvoker实例
//二 获取代理
-->JavassistProxyFactory.getProxy(Invoker<T> invoker, Class<?>[] interfaces)//invoker:上边的MockClusterInvoker实例, interfaces:[interface com.alibaba.dubbo.demo.DemoService, interface com.alibaba.dubbo.rpc.service.EchoService]
-->Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker))
-->Proxy.getProxy(ClassLoader cl, Class<?>... ics)//使用javassist获取一个动态类
-->new InvokerInvocationHandler(invoker)//invoker:上边的MockClusterInvoker实例
消费者发布的时候总体做了两件事:创建 Invoker
和 创建 API 接口的代理对象
。
2.1 创建Invoker
1. 获取注册中心:创建 ZkClient 实例,连接 zk
//1 获取注册中心:创建ZkClient实例,连接zk
-->Registry registry = registryFactory.getRegistry(url)
-->AbstractRegistryFactory.getRegistry(URL url)
-->ZookeeperRegistryFactory.createRegistry(URL url)
-->new ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter)
-->ZkclientZookeeperTransporter.connect(URL url)
-->new ZkclientZookeeperClient(URL url)
-->new ZkClient(url.getBackupAddress())
-->AbstractRegistryFactory.Map<String, Registry> REGISTRIES.put("zookeeper://10.211.55.5:2181/com.alibaba.dubbo.registry.RegistryService", 上边的ZookeeperRegistry实例)
与provider相同,不再赘述。
2. 向注册中心注册 consumer 服务
//2 向注册中心注册服务
-->registry.register(url)
-->ZookeeperRegistry.doRegister(URL url)
-->AbstractZookeeperClient.create(String path, boolean ephemeral)
consumer 完成注册后,会在 zk 上创建节点(url 解码后):
/dubbo
- /com.alibaba.dubbo.demo.DemoService
-- /consumers
--- /consumer://10.10.10.10/com.alibaba.dubbo.demo.DemoService?application=demo-consumer&category=consumers&check=false&dubbo=2.0.0&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=25267&side=consumer×tamp=1510225913509
3. 使用 RegistryDirectory 订阅 providers、configurators、routers 节点
其中,configurators
节点用于覆盖配置(实现“热配置”),routers
节点用于配置路由信息。这里重点说一下 providers
节点,该节点下存储着 DemoService 的服务提供者列表,当该列表发生变化时(添加 provider 机器或者宕机),会通知 consumer 进行 refreshInvoker
操作。看一下 RegistryDirectory 订阅 providers 的逻辑。
//3.1 会获取当前节点下已经存在的字节点(第一次服务发现发生在这里),添加子节点变化监听器
-->List<String> children = zkClient.addChildListener(path, zkListener)
-->AbstractRegistry.notify(URL url, NotifyListener listener, List<URL> urls)
-->saveProperties(url)
-->RegistryDirectory.notify(List<URL> urls)
//仅仅针对的是providers
-->refreshInvoker(List<URL> invokerUrls)
-->toInvokers(List<URL> urls
-->ProtocolFilterWrapper.refer(Class<T> type, URL url)
-->DubboProtocol.refer(Class<T> serviceType, URL url)
//3.1.1 创建ExchangeClient,对第一次服务发现providers路径下的相关url建立长连接
-->getClients(URL url)
-->getSharedClient(URL url)
-->ExchangeClient exchangeClient = initClient(url)
-->Exchangers.connect(url, requestHandler)
-->HeaderExchanger.connect(URL url, ExchangeHandler handler)
-->new DecodeHandler(new HeaderExchangeHandler(handler)))
-->Transporters.connect(URL url, ChannelHandler... handlers)
-->NettyTransporter.connect(URL url, ChannelHandler listener)
-->new NettyClient(url, listener)
-->new MultiMessageHandler(HeartbeatHandler(AllChannelHandler(handler)))
-->getChannelCodec(url)//获取Codec2,这里是DubboCountCodec实例
-->doOpen()//开启netty客户端
-->doConnect()//连接服务端,建立长连接
-->new HeaderExchangeClient(Client client, boolean needHeartbeat)//上述的NettyClient实例,needHeartbeat:true
-->startHeatbeatTimer()//启动心跳计数器
-->ReferenceCountExchangeClient(ExchangeClient client, ConcurrentMap<String, LazyConnectExchangeClient> ghostClientMap)/
-->Map<String, ReferenceCountExchangeClient> referenceClientMap.put("10.10.10.10:20880", 上边的ReferenceCountExchangeClient实例)
//3.2 创建DubboInvoker
-->new DubboInvoker(Class<T> serviceType, URL url, ExchangeClient[] clients, Set<Invoker<?>> invokers)
-->DubboProtocol.Set<Invoker<?>> invokers.add(上边的DubboInvoker实例)
-->ProtocolFilterWrapper.buildInvokerChain(final Invoker<T> invoker, String key, String group)
-->new InvokerDelegete(Invoker<T> invoker, URL url, URL providerUrl)
//3.3 将创建出来的Invoker缓存起来
-->newUrlInvokerMap.put("dubbo://10.10.10.10:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-consumer&check=false&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=16001®ister.ip=10.10.10.10&remote.timestamp=1510127991625&side=consumer×tamp=1510128022123", 上边的InvokerDelegate实例)
-->toMethodInvokers(newUrlInvokerMap)
-->Map<String, List<Invoker<T>>> newMethodInvokerMap:{sayHello=[InvokerDelegete实例], *=[InvokerDelegete实例]}
总体流程 :
- 首先添加 provider 子节点监听器,同时进行
第一次服务发现
,找出当前注册在 zk 上的 provider 节点。- 然后创建
ReferenceCountExchangeClient
,为每一个provider
创建一条Netty
长连接(开启了Netty
客户端并连接 provider 的Netty
服务端)- 开启心跳定时器
- 缓存 ReferenceCountExchangeClient
- 将创建出来的 ReferenceCountExchangeClient 封装到 DubboInvoker 实例中
- 根据条件获取相关的 filter,之后使用这些 fiter 对 DubboInvoker 实例进行链式包装,将包装后的 DubboInvoker 封装到 InvokerDelegete 中
- 最后将该 InvokerDelegete 实例按照方法名封装到
Map<String, List<Invoker<T>>> newMethodInvokerMap
中。(该 map 也是 consumer 调用 provider 时,获取 provider 实例的地方,该 map 是 RegistryDirectory 的一个属性,所以我们可以将 RegistryDirectory 看做是一个 provider 的客户端缓存器
)
Directory.List<Router> routers 会在两个地方被设置
:
- 初次创建 Directory 实例时,在 Directory 构造器中进行设置;
- notify 的时候会进行 routers 的重新设置。
关于 Directory 的设计,后续分析
4. 将 directory 封装成一个 ClusterInvoker(MockClusterInvoker)
//4 将directory封装成一个ClusterInvoker(MockClusterInvoker)
-->cluster.join(directory)
-->Cluster$Adaptive.join(directory)
-->ExtensionLoader.getExtensionLoader(Cluster.class).getExtension("failover")//MockClusterWrapper包装FailoverCluster
-->MockClusterWrapper.join(Directory<T> directory)
-->FailoverCluster.join(Directory<T> directory)
-->new FailoverClusterInvoker<T>(directory)
-->MockClusterInvoker(Directory<T> directory, Invoker<T> invoker)//invoker:上边的FailoverClusterInvoker实例
Dubbo 实现了集群容错功能。在 consumer 发布的最后流程中,实现了集群容错。
- 首先根据 Dubbo SPI 机制获取指定类型的
Cluster
实现,这里默认是FailoverCluster
(失败重试机制);- 之后将上边的
RegistryDirectory
封装到FailoverClusterInvoker
实例中;- 最后创建一个
MockClusterInvoker
实例,封装了RegistryDirectory
和FailoverClusterInvoker
。(MockClusterInvoker
用于实现服务降级
功能)
到这里,consumer 创建 Invoker 的源码就结束了。总结一下
:
- 获取注册中心:创建 ZkClient 实例,连接 zk
- 向注册中心注册 consumer 服务
- 使用 RegistryDirectory 订阅 providers、configurators、routers 节点
3.1. 添加 provider 子节点监听器,同时进行第一次服务发现,找出当前注册在 zk 上的 provider 节点
3.1.1. 创建 ReferenceCountExchangeClient,为每一个 provider 创建一条 Netty 长连接(开启了 Netty 客户端并连接 provider 的 Netty 服务端)
3.1.2. 开启心跳定时器
3.2. 根据条件获取相关的 filter,之后使用这些 fiter 对DubboInvoker
实例进行链式包装,将包装后的 DubboInvoker 封装到 InvokerDelegete 中
3.3. 最后将该 InvokerDelegete 实例按照方法名封装到Map<String, List<Invoker<T>>> newMethodInvokerMap
中
- 将 directory 封装成一个
ClusterInvoker
(MockClusterInvoker)4.1 首先根据 Dubbo SPI 机制获取指定类型的 Cluster 实现,这里默认是 FailoverCluster(失败重试机制);
4.2 之后将上边的 RegistryDirectory 封装到 FailoverClusterInvoker 实例中;
4.3 最后创建一个 MockClusterInvoker 实例,封装了 RegistryDirectory 和 FailoverClusterInvoker。(MockClusterInvoker用于实现服务降级功能)
我们可以看到,最终获取到的 Invoker 是 MockClusterInvoker 实例
。
关于 Cluster 的设计,后续分析
2.2 创建API接口的代理对象
//二 获取代理
-->JavassistProxyFactory.getProxy(Invoker<T> invoker, Class<?>[] interfaces)//invoker:上边的MockClusterInvoker实例, interfaces:[interface com.alibaba.dubbo.demo.DemoService, interface com.alibaba.dubbo.rpc.service.EchoService]
-->Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker))
-->Proxy.getProxy(ClassLoader cl, Class<?>... ics)//使用javassist获取一个动态类
-->new InvokerInvocationHandler(invoker)//invoker:上边的MockClusterInvoker实例
获取 API 接口代理的逻辑比较简单,注意这里的 Proxy 是 com.alibaba.dubbo.common.bytecode.Proxy
,而非 JDK 的 Proxy。
这里首先调用 Proxy.getProxy(interfaces)
获取到一个创建代理的工厂类 com.alibaba.dubbo.common.bytecode.Proxy0
,如下:
package com.alibaba.dubbo.common.bytecode;
import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.common.bytecode.Proxy;
import com.alibaba.dubbo.common.bytecode.proxy0;
import java.lang.reflect.InvocationHandler;
public class Proxy0 extends Proxy implements ClassGenerator.DC {
public Object newInstance(InvocationHandler invocationHandler) {
return new proxy0(invocationHandler);
}
}
之后调用了 Proxy0#newInstance
方法,创建了一个 com.alibaba.dubbo.common.bytecode.proxy0
实例,该实例就是最终的 DemoService 的代理对象。
DemoService demoService = (DemoService) context.getBean("demoService");
这里的 demoService 就是上述的 com.alibaba.dubbo.common.bytecode.proxy0
实例。
package com.alibaba.dubbo.common.bytecode;
import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.demo.DemoService;
import com.alibaba.dubbo.rpc.service.EchoService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class proxy0 implements EchoService, DemoService {
public static Method[] methods;
private InvocationHandler handler;
public String sayHello(String string) {
Object[] arrobject = new Object[]{string};
Object object = this.handler.invoke(this, methods[0], arrobject);
return (String)object;
}
public Object $echo(Object object) {
Object[] arrobject = new Object[]{object};
Object object2 = this.handler.invoke(this, methods[1], arrobject);
return object2;
}
public proxy0() {
}
public proxy0(InvocationHandler invocationHandler) {
this.handler = invocationHandler;
}
}
可以看到,当调用 proxy0#sayHello
时,实际上其内部执行的是 InvocationHandler#invoke
,来看一下 InvocationHandler。
public class InvokerInvocationHandler implements InvocationHandler {
private final Invoker<?> invoker; //上边的MockClusterInvoker实例
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
...
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
}
InvocationHandler#invoke 调用的又是 MockClusterInvoker#invoke 方法。到此为止,整个服务引用的源码分析就完成了。
网友评论