一、服务暴露简图
总体流程:(默认配置情况下)
- 首先 ServiceConfig 类拿到对外提供服务的实际类 ref(如:DemoServiceImpl);
- 然后通过 JavassistProxyFactory 类的 getInvoker 方法将 ref 封装到一个 AbstractProxyInvoker 实例;
- 最后通过 InjvmProtocol(本地暴露)和 DubboProtocol(远程暴露)将AbstractProxyInvoker 实例转换成 InjvmExporter 和 DubboExporter。
注意
- provider 端的
Invoker
封装了对ref
的调用逻辑;Exporter
是用于管理Invoker
的生命周期的。
public interface Invoker extends Node {
/** get service interface. */
Class getInterface();
/** invoke. */
Result invoke(Invocation invocation) throws RpcException;
}
public interface Exporter {
/** get invoker. */
Invoker getInvoker();
/** unexport. 销毁 Invoker */
void unexport();
}
- 服务暴露第一步,会使用
ProxyFactory#getInvoker(...)
将 ref 封装到AbstractProxyInvoker
实例中,该实例是在ProxyFactory#getInvoker(...)
中创建的匿名内部类,并复写了AbstractProxyInvoker#doInvoker
方法
public abstract class AbstractProxyInvoker implements Invoker {
// 真实对象 ref, eg. DemoServiceImpl
private final T proxy;
// 提供模板方法:1. 调用子类发起请求 2. 包装响应为 RpcResult
@Override
public Result invoke(Invocation invocation) throws RpcException {
return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
}
// 子类覆写的真正调用的方法
protected abstract Object doInvoke(T proxy, String methodName, Class>[] parameterTypes, Object[] arguments) throws Throwable;
}
public class JavassistProxyFactory extends AbstractProxyFactory {
@Override
public Invoker getInvoker(T proxy, Class type, URL url) {
// wrapper:通过动态生成一个真实的服务提供者(DemoServiceImpl)的wrapper类,来避免反射调用
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class>[] parameterTypes,
Object[] arguments) throws Throwable {
// 直接调用wrapper,wrapper底层调用DemoServiceImpl
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
}
这样服务暴露的第一步,我们会得到一个由 JavassistProxyFactory#getInvoker(...)
创建的匿名内部类 AbstractProxyInvoker
实例。
- 服务暴露的第二步,会使用
Protocol#export(Invoker
将第一步得到的invoker) AbstractProxyInvoker
实例封装到Exporter
中(Invoker
与Exporter
一对一,后续Exporter
会管理Invoker
的生命周期,并且作为Invoker
的门面与外部沟通),我们只看远程暴露,服务暴露第二步之后,会获得一个 DubboExporter 实例
public abstract class AbstractExporter implements Exporter {
// 封装了 Invoker,用于管理该 Invoker 的生命周期
private final Invoker invoker;
@Override
public Invoker getInvoker() {
return invoker;
}
@Override
public void unexport() {
...
getInvoker().destroy();
}
}
public class DubboExporter extends AbstractExporter {
// serviceKey: group/path:version:port
private final String key;
/**
* 注意:exporterMap 对象实际上持有的是 AbstractProtocol 中的 exporterMap 对象引用
* key: serviceKey
* value: 具体的 Exporter 实例,eg. DubboExporter
*/
private final Map> exporterMap;
public DubboExporter(Invoker invoker, String key, Map> exporterMap) {
super(invoker); // 存储该 DubboExporter 实例管理的 Invoker 实例
this.key = key;
this.exporterMap = exporterMap;
}
@Override
public void unexport() {
super.unexport();
exporterMap.remove(key);
}
}
- RegistryProtocol 实际上是其他具体 Protocol(eg. DubboProtocol)的 AOP 类:
- 首先会调用具体 Protocol#export(...)
之后获取 Registry,然后进行注册,最后监听 override 数据。
(这一步的三个操作就是 AOP 的目的)
// 具体 Protocol 的 AOP 类
public class RegistryProtocol implements Protocol {
// 具体协议
private Protocol protocol;
@Override
public Exporter export(final Invoker originInvoker) throws RpcException {
// 1. 做具体的 Protocol 的暴露操作
ExporterChangeableWrapper exporter = doLocalExport(originInvoker);
...
// 2. 获取注册中心
Registry registry = getRegistry(originInvoker);
...
// 3. 注册
register(registryUrl, registeredProviderUrl);
// 4. 订阅 the override data
...
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
//Ensure that a new exporter instance is returned every time export
return new DestroyableExporter(exporter, originInvoker, overrideSubscribeUrl, registeredProviderUrl);
}
private ExporterChangeableWrapper doLocalExport(Invoker originInvoker) {
...
// 调用具体 Protocol 暴露服务
protocol.export(invokerDelegete);
...
return exporter;
}
...
}
public abstract class AbstractProtocol implements Protocol {
/**
* 该容器是当请求到来时获取 Exporter 的地方
* key: serviceKey
* value: 具体的 Exporter 实例,eg. DubboExporter
*/
protected final Map> exporterMap = new ConcurrentHashMap>();
...
}
public class DubboProtocol extends AbstractProtocol {
@Override
public Exporter export(Invoker invoker) throws RpcException {
...
// 获取 serviceKey:group/path:version:port
String key = serviceKey(url);
// 将 invoker 存储到 DubboExporter 中,并且让 DubboExporter 持有 AbstractProtocol#exporterMap 的对象引用(后续 DubboExporter 在做销毁操作时,会主动从该 exporterMap 中删除对象,做到逻辑高内聚)
DubboExporter exporter = new DubboExporter(invoker, key, exporterMap);
// 将 {serviceKey:具体的Exporter} 存储到 AbstractProtocol#exporterMap 中,当请求到来时,来这里根据 serviceKey 获取 Exporter
exporterMap.put(key, exporter);
...
// 开启 netty 服务
openServer(url);
...
return exporter;
}
// 真正的 netty 请求处理器
private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {
@Override
public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
Invocation inv = (Invocation) message;
// 当请求到来时,找到真正要处理请求的那个Invoker
Invoker> invoker = getInvoker(channel, inv);
...
// 发起调用
return invoker.invoke(inv);
}
throw new RemotingException(...);
}
// 接收到请求时的处理逻辑
@Override
public void received(Channel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
reply((ExchangeChannel) channel, message);
} else {
...
}
}
...
};
/**
* 当请求到来时,找到真正要处理请求的那个Invoker
* 1. 首先根据请求参数 Channel channel, Invocation inv 组装 serviceKey=group/path:version:port
* 2. 根据 serviceKey 从 ExporterMap 中获取 Exporter
* 3. 从Exporter 中获取 Invoker
*/
Invoker> getInvoker(Channel channel, Invocation inv) throws RemotingException {
...
/**
* 1. 根据请求参数 Channel channel, Invocation inv 组装 serviceKey=group/path:version:port
* port 从 Channel 中获取;path、version、group 从 Invocation 中获取
*/
int port = channel.getLocalAddress().getPort();
String path = inv.getAttachments().get(Constants.PATH_KEY);
...
// group/path:version:port
String serviceKey = serviceKey(port, path, inv.getAttachments().get(Constants.VERSION_KEY), inv.getAttachments().get(Constants.GROUP_KEY));
/**
* 2. 从 exporterMap 中获取 Exporter
*/
DubboExporter> exporter = (DubboExporter>) exporterMap.get(serviceKey);
if (exporter == null)
throw new RemotingException(...);
/**
* 3. 从Exporter 中获取 Invoker
*/
return exporter.getInvoker();
}
}
整个流程:当 netty 接收到一个请求时
- 首先根据请求参数 Channel channel, Invocation inv 组装 serviceKey=
group/path:version:port
- 根据 serviceKey 从
AbstractProtocol#exporterMap
中获取 Exporter(DubboExporter
实例,服务暴露第二步做了存储)- 从 Exporter 中获取 Invoker(
AbstractInvoker
实例,服务暴露第二步做了存储)- 调用
Invoker#invoke(...)
调用对应的ref.xxxmethod(...)
(服务暴露第一步做了初始化)
二、服务暴露源码梯形图
ServiceBean.onApplicationEvent(ApplicationEvent event)
-->ServiceConfig.export()
-->doExport()
-->doExportUrls()
-->doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs)
-->exportLocal(url)
//1.1 将实现类ref封装成Invoker
-->JavassistProxyFactory.getInvoker(T proxy, Class type, URL url)
proxy:DemoServiceImpl实例(即ref实例)
type:interface com.alibaba.dubbo.demo.DemoService
url:injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=3141&side=provider×tamp=1510021401013
-->Wrapper.getWrapper(Class DemoServiceImpl)
-->new AbstractProxyInvoker(proxy, type, url)
//1.2 将实现类Invoker暴露为Exporter
-->ProtocolFilterWrapper.buildInvokerChain(final Invoker invoker, String key, String group)
组建invoker链,实际上只有最后一个是真正的AbstractProxyInvoker实例,前边的都是filter。
invoker:AbstractProxyInvoker实例
key:service.filter
group:provider
-->InjvmProtocol.export(Invoker invoker)
invoker:经过filter包装的invoker
-->new InjvmExporter(Invoker invoker, String key, Map> exporterMap)
invoker:经过filter包装的invoker
key:com.alibaba.dubbo.demo.DemoService
exporterMap:传入时为空,构造器执行后为{"com.alibaba.dubbo.demo.DemoService", 当前的InjvmExporter实例}
-->List> exporters.add(上述的exporter)
//2.1 将实现类ref封装成Invoker
-->JavassistProxyFactory.getInvoker(T proxy, Class type, URL url)
proxy:DemoServiceImpl实例(即ref实例)
type:interface com.alibaba.dubbo.demo.DemoService
-->Wrapper.getWrapper(Class DemoServiceImpl)
-->new AbstractProxyInvoker(proxy, type, url)
-->RegistryProtocol.export(final Invoker originInvoker)
originInvoker:上述的AbstractProxyInvoker实例
//2.2 将invoker转化为exporter
-->doLocalExport(originInvoker)
-->new InvokerDelegete(Invoker invoker, URL url)
invoker:原始的AbstractProxyInvoker实例
-->ProtocolFilterWrapper.buildInvokerChain(final Invoker invoker, String key, String group)
组建invoker链,实际上只有最后一个是真正的InvokerDelegete实例,前边的都是filter
invoker:InvokerDelegete实例
key:service.filter
group:provider
-->DubboProtocol.export(Invoker invoker)
invoker:经过filter包装的InvokerDelegete实例
-->new DubboExporter(Invoker invoker, String key, Map> exporterMap)
invoker:经过filter包装的InvokerDelegete实例
key:com.alibaba.dubbo.demo.DemoService:20880 (group/path:version:port)
exporterMap:传入时为空,构造器执行后又执行了put,为{"com.alibaba.dubbo.demo.DemoService:20880", 当前的DubboExporter实例}
//2.3 开启netty服务端监听客户端请求
-->openServer(URL url)
-->createServer(URL url)
-->HeaderExchanger.bind(URL url, ExchangeHandler handler)
handler:DubboProtocol.requestHandler
-->new DecodeHandler(new HeaderExchangeHandler(handler)))
-->NettyTransporter.bind(URL url, ChannelHandler listener)
listener:上边的DecodeHandler实例
-->new NettyServer(URL url, ChannelHandler handler)
-->ChannelHandler.wrapInternal(ChannelHandler handler, URL url)
handler:上边的DecodeHandler实例
-->new MultiMessageHandler(HeartbeatHandler(AllChannelHandler(handler)))
-->getChannelCodec(url)//获取Codec2,这里是DubboCountCodec实例
-->doOpen()//开启netty服务
-->new HeaderExchangeServer(Server server)
server:上述的NettyServer
-->startHeatbeatTimer()
-->new ExporterChangeableWrapper(Exporter exporter, Invoker originInvoker)
exporter:上述的DubboExporter实例
originInvoker:原始的AbstractProxyInvoker实例
//2.4 创建Registry:创建zkclient,连接zk
-->getRegistry(final Invoker> originInvoker)
-->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())//这里是10.211.55.5:2181
-->AbstractRegistryFactory.Map REGISTRIES.put("zookeeper://10.211.55.5:2181/com.alibaba.dubbo.registry.RegistryService", 上边的ZookeeperRegistry实例)
//2.5 向注册中心注册服务
-->registry.register(registedProviderUrl)
-->ZookeeperRegistry.doRegister(URL url)
-->AbstractZookeeperClient.create(String path, boolean ephemeral)
//2.6 订阅override数据
-->ZookeeperRegistry.doSubscribe(final URL url, final NotifyListener listener)
//2.7 创建新的Exporter实例
-->new Exporter()//包含了上边的ExporterChangeableWrapper exporter实例 + ZookeeperRegistry实例
服务暴露的实机:默认为spring发布上下文刷新事件时。
默认情况下,整个服务暴露会发生本地暴露
和远程暴露
两次暴露。
2.1 本地暴露
1. 使用 JavassistProxyFactory 将实现类 ref(DemoServiceImpl)封装成AbstractProxyInvoker实例
1.1 将实现类ref封装成Invoker
-->JavassistProxyFactory.getInvoker(T proxy, Class type, URL url)
proxy:DemoServiceImpl实例(即ref实例)
type:interface com.alibaba.dubbo.demo.DemoService
url:injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=3141&side=provider×tamp=1510021401013
-->Wrapper.getWrapper(Class DemoServiceImpl)
-->new AbstractProxyInvoker(proxy, type, url)
看一下核心代码:
public class JavassistProxyFactory extends AbstractProxyFactory {
......
public Invoker getInvoker(T proxy, Class type, URL url) {
// 创建 wrapper 实例
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
// 创建 Invoker 实例
return new AbstractProxyInvoker(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class>[] parameterTypes,
Object[] arguments) throws Throwable {
// Invoker 调用 wrapper,wrapper 调用 proxy(即 ref,eg. DemoServiceImpl)
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
}
注意
:在 JavassistProxyFactory#getInvoker 中,首先根据 ref 生成一个 Wrapper,之后将 wrapper 封装在 AbstractProxyInvoker 类中。看一下这个 Wrapper 类的核心代码(com.alibaba.dubbo.common.bytecode.Wrapper0
,该类是通过 javassist 生成的)。
package com.alibaba.dubbo.common.bytecode;
import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.common.bytecode.NoSuchMethodException;
import com.alibaba.dubbo.common.bytecode.NoSuchPropertyException;
import com.alibaba.dubbo.common.bytecode.Wrapper;
import com.alibaba.dubbo.demo.DemoService;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public class Wrapper0 extends Wrapper implements ClassGenerator.DC {
...
/**
* @param object 实现类ref,eg. DemoServiceImpl
* @param string 方法名称
* @param arrclass 参数类型
* @param arrobject 参数值
* @return 调用返回值
* @throws java.lang.reflect.InvocationTargetException
*/
public Object invokeMethod(Object object, String string, Class[] arrclass, Object[] arrobject) throws InvocationTargetException {
DemoService demoService;
try {
demoService = (DemoService)object;
} catch (Throwable throwable) {
throw new IllegalArgumentException(throwable);
}
try {
if ("sayHello".equals(string) && arrclass.length == 1) {
return demoService.sayHello((String)arrobject[0]);
}
} catch (Throwable throwable) {
throw new InvocationTargetException(throwable);
}
throw new NoSuchMethodException(new StringBuffer().append("Not found method \"").append(string).append("\" in class com.alibaba.dubbo.demo.DemoService.").toString());
}
...
}
Dubbo 通过“硬编码”的方式(实际上是 Javassist 动态生成)生成一个 wrapper 类,在 wrapper 类内部又调用了具体实现类的具体方法,通过这样的方式避免了反射调用。
2. 使用 ProtocolFilterWrapper 将 AbstractProxyInvoker 实例进行 Filter 链的包装,之后使用 InjvmProtocol 暴露为 InjvmExporter 实例
//1.2 将实现类Invoker暴露为Exporter
-->ProtocolFilterWrapper.buildInvokerChain(final Invoker invoker, String key, String group)
组建invoker链,实际上只有最后一个是真正的AbstractProxyInvoker实例,前边的都是filter。
invoker:AbstractProxyInvoker实例
key:service.filter
group:provider
-->InjvmProtocol.export(Invoker invoker)
invoker:经过filter包装的invoker
-->new InjvmExporter(Invoker invoker, String key, Map> exporterMap)
invoker:经过filter包装的invoker
key:com.alibaba.dubbo.demo.DemoService
exporterMap:传入时为空,构造器执行后为{"com.alibaba.dubbo.demo.DemoService", 当前的JvmExporter实例}
-->List> exporters.add(上述的exporter)
这里首先使用 Dubbo SPI 机制,获取到了相应的 filter,之后使用这些 filter 对 AbstractProxyInvoker 实例进行链式包装。最后通过 InjvmProtocol 将包装后的 AbstractProxyInvoker 实例暴露为 InjvmExporter 实例。(实际上,Exporter
是用于管理 Invoker
的生命周期的)
最终生成的InjvmExporter实例包含如下属性:
key = "com.alibaba.dubbo.demo.DemoService"
exporterMap: { "com.alibaba.dubbo.demo.DemoService" -> 当前的InjvmExporter实例 }
Invoker invoker = 被filter进行递归包裹后的Invoker
到这里,整个本地暴露就完成了。总结一下 整体流程
:
- 首先根据 ref 生成一个 wrapper 类,之后将该 wrapper 类封装到 AbstractProxyInvoker 实例中;
- 使用符合条件的 filter 对 AbstractProxyInvoker 进行链式包装,最后将包装后的 AbstractProxyInvoker 实例封装到 InjvmExporter 实例中。
2.2 远程暴露
1. 使用 JavassistProxyFactory 将实现类 ref(DemoServiceImpl)封装成 AbstractProxyInvoker 实例
与本地暴露类似,不再赘述。
//2.1 将实现类ref封装成Invoker
-->JavassistProxyFactory.getInvoker(T proxy, Class type, URL url)
proxy:DemoServiceImpl实例(即ref实例)
type:interface com.alibaba.dubbo.demo.DemoService
-->Wrapper.getWrapper(Class DemoServiceImpl)
-->new AbstractProxyInvoker(proxy, type, url)
2. 使用 ProtocolFilterWrapper 将 AbstractProxyInvoker 实例进行 Filter 链的包装,之后使用 DubboProtocol 暴露为 DubboExporter 实例
-->new InvokerDelegete(Invoker invoker, URL url)
invoker:原始的AbstractProxyInvoker实例
-->ProtocolFilterWrapper.buildInvokerChain(final Invoker invoker, String key, String group)
组建invoker链,实际上只有最后一个是真正的InvokerDelegete实例,前边的都是filter
invoker:InvokerDelegete实例
key:service.filter
group:provider
-->DubboProtocol.export(Invoker invoker)
invoker:经过filter包装的InvokerDelegete实例
-->new DubboExporter(Invoker invoker, String key, Map> exporterMap)
invoker:经过filter包装的InvokerDelegete实例
key:com.alibaba.dubbo.demo.DemoService:20880 (group/servicename:version:port)
exporterMap:传入时为空,构造器执行后又执行了put,为{"com.alibaba.dubbo.demo.DemoService:20880", 当前的DubboExporter实例}
与本地暴露类似,最终得到的DubboExporter实例包含如下属性:
key:com.alibaba.dubbo.demo.DemoService:20880
invoker:“InvokerDelegete的filter对象”(InvokerDelegete只是对AbstractProxyInvoker实例的简单封装)
exporterMap:{ "com.alibaba.dubbo.demo.DemoService:20880" -> 当前的DubboExporter实例 }
实际上key的完整值为:group/path:version:port
(如果都配置了的话)。
注意
:最后在 DubboProtocol 的属性 Map
中也会存储 { key -> 当前的 DubboExporter 实例 }
,将来 Netty
的 handler
会根据 consumer
的请求参数组建 key,然后从这个 exporterMap 中寻找 Exporter 实例,然后从 Exporter 实例中获取相关的被 filter 链包装的 AbstractProxyInvoker 实例,进行调用。
3. 开启 Netty 服务端监听客户端请求
//2.3 开启netty服务端监听客户端请求
-->openServer(URL url)
-->createServer(URL url)
-->HeaderExchanger.bind(URL url, ExchangeHandler handler)
handler:DubboProtocol.requestHandler
-->new DecodeHandler(new HeaderExchangeHandler(handler)))
-->NettyTransporter.bind(URL url, ChannelHandler listener)
listener:上边的DecodeHandler实例
-->new NettyServer(URL url, ChannelHandler handler)
-->ChannelHandler.wrapInternal(ChannelHandler handler, URL url)
handler:上边的DecodeHandler实例
-->new MultiMessageHandler(HeartbeatHandler(AllChannelHandler(handler)))
-->getChannelCodec(url)//获取Codec2,这里是DubboCountCodec实例
-->doOpen()//开启netty服务
-->new HeaderExchangeServer(Server server)
server:上述的NettyServer
-->startHeatbeatTimer()
这里首先构建并创建各种 handler,层层包装 DubboProtocol.requestHandler
实例(该实例就是 Netty 最终用来处理业务逻辑的那个 handler)。然后启动 Netty 服务端。最后启动心跳。
这里说一下 心跳机制:
- provider:Dubbo 的心跳默认是在 60s 内如果没有接收到消息,就会发送心跳消息,如果连着3次(180s)没有收到心跳响应,provider 会关闭 channel。(用于回收资源,会执行 Netty 的 channel 的优雅关闭操作)
- consumer:Dubbo 的心跳默认是在 60s 内如果没有接收到消息,就会发送心跳消息,如果连着3次(180s)没有收到心跳响应,consumer会进行重连。
4. 创建 Registry:创建zkclient,连接zk
//2.4 创建Registry:创建zkclient,连接zk
-->getRegistry(final Invoker> originInvoker)
-->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())//这里是10.211.55.5:2181
-->AbstractRegistryFactory.Map REGISTRIES.put("zookeeper://10.211.55.5:2181/com.alibaba.dubbo.registry.RegistryService", 上边的ZookeeperRegistry实例)
5. 向注册中心注册服务
//2.5 向注册中心注册服务
-->registry.register(registedProviderUrl)
-->ZookeeperRegistry.doRegister(URL url)
-->AbstractZookeeperClient.create(String path, boolean ephemeral)
注册完成之后,就会在 zk 上创建节点(url 解码后如下):
/dubbo
- /com.alibaba.dubbo.demo.DemoService
-- /providers
--- /dubbo://10.10.10.10:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=3508&side=provider×tamp=1510023456461
6.订阅 override 数据
//2.6 订阅 override 数据
-->ZookeeperRegistry.doSubscribe(final URL url, final NotifyListener listener)
override
数据是用于做配置覆盖
的(改变的是 /dubbo/servicekey/configurators
节点),实现 “热配置”
功能。
到这里,远程暴露也就完成了。
流程总结
- 首先根据 ref 生成一个 wrapper 类,之后将该 wrapper 类封装到 AbstractProxyInvoker 实例中;
- 使用符合条件的 filter 对 AbstractProxyInvoker 进行链式包装,最后将包装后的 AbstractProxyInvoker 实例封装到 DubboExporter 实例(DubboExporter 用于管理 AbstractProxyInvoker 实例的生命周期)中;
- 开启 Netty 服务端监听客户端请求;
- 创建 zkclient,连接 zk;
- 向注册中心注册服务;
- 订阅 override 数据。