Official website: http://dubbo.apache.org/zh-cn/docs/source_code_guide/export-service.html
暴露流程:
- ClassPathXmlApplicationContext加载provider的xml文件
- 解析<dubbo:service interface=“xxx.xxx” ref=“xxx”/>到ServiceConfig对象,并且进行服务暴露
- 启动Netty服务端,向外提供tcp服务接口
- 注册服务到注册中心
// 在这里开始 ServiceBean.java
// 不延迟导出:onApplicationEvent()
// 延迟导出:afterPropertiesSet()
public void onApplicationEvent(ContextRefreshedEvent event) {
if (isDelay() && !isExported() && !isUnexported()) {
...
export();
}
}
// 不延迟导出:onApplicationEvent()
// 延迟导出:afterPropertiesSet()
public void afterPropertiesSet() throws Exception {
...
if (!isDelay()) {
export();
}
}
// 是否延迟导出
private boolean isDelay() {
// 针对单个服务配置延迟 eg. @Service(delay = 4000)
// 默认delay值为0(启动会设置成null)
Integer delay = getDelay();
// 针对provider配置延迟 eg. <dubbo:provider filter="dubboFilter4Provider" delay="20"/>
ProviderConfig provider = getProvider();
if (delay == null && provider != null) {
delay = provider.getDelay();
}
// true: (delay == null || delay == -1)
// false: delay > 0
return supportedApplicationListener && (delay == null || delay == -1);
}
// @Parameter的excluded为true表示不需要添加到URL的parameters中
@Parameter(excluded = true)
public boolean isExported() {
return exported;
}
ServiceBean实现了ApplicationListener#onApplicationEvent(E),在容器初始化完成后执行。
ServiceBean也实现了InitializingBean#afterPropertiesSet(),可以实现延迟导出。
// 检查是否需要导出。不导出,直接返回
// 是否需要延迟导出。需要,则启动定时任务
// ServiceConfig.export()
public synchronized void export() {
if (provider != null) {
// 配置 @Service(export = false) 时,export会设置被设置成null
// 配置 @Service(export = true) 时,export 才会为 true
// ??? 但对以下的逻辑都没影响,是不是认为该参数没有作用的。
if (export == null) {
// 设置provider级的export是不会设置成null的
// eg. <dubbo:provider export="false" />
export = provider.getExport();
}
if (delay == null) {
delay = provider.getDelay();
}
}
// true: export == false
// export == false时,该服务不可被远程调用
if (export != null && !export) {
return;
}
if (delay != null && delay > 0) {
// delay > 0 休眠N毫秒再导出
// 单线程定时调度线程池
// private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));
delayExportExecutor.schedule(new Runnable() {
public void run() {
doExport();
}
}, delay, TimeUnit.MILLISECONDS);
} else {
doExport();
}
}
// 检测 <dubbo:service> 标签的 interface 属性合法性
// 初始化application、module、registries、monitor、protocols等变量
// 检查以上对象是否为空
// ServiceConfig#doExport()
protected synchronized void doExport() {
if (unexported) {
throw new IllegalStateException("Already unexported!");
}
if (exported) {
return;
}
exported = true;
// 检测 <dubbo:service> 标签的 interface 属性合法性
if (interfaceName == null || interfaceName.length() == 0) {
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
}
// 为ProviderConfig的设置property,从环境变量或配置文件中取dubbo.provider.<id>.<property> 和 dubbo.provider.<property>
// 先从系统环境变量获取,获取不到,再从配置文件种获取
// 配置文件路径可以通过启动参数:dubbo.properties.file或dubbo.properties配置
checkDefault();
// 初始化application、module、registries、monitor、protocols等变量
if (provider != null) {
if (application == null) {
application = provider.getApplication();
}
if (module == null) {
module = provider.getModule();
}
if (registries == null) {
registries = provider.getRegistries();
}
if (monitor == null) {
monitor = provider.getMonitor();
}
if (protocols == null) {
protocols = provider.getProtocols();
}
}
...
if (application != null) {
if (registries == null) {
registries = application.getRegistries();
}
if (monitor == null) {
monitor = application.getMonitor();
}
}
// TODO 这句话有什么作用
if (ref instanceof GenericService) {
interfaceClass = GenericService.class;
if (StringUtils.isEmpty(generic)) {
generic = Boolean.TRUE.toString();
}
} else {
try {
// 取得Class类类型对象
interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
checkInterfaceAndMethods(interfaceClass, methods);
checkRef();
generic = Boolean.FALSE.toString();
}
// 已废弃,请使用stub
if (local != null) {
// 此处的代码和下一个 if 分支的代码基本一致,这里省略
}
if (stub != null) {
if ("true".equals(stub)) {
stub = interfaceName + "Stub";
}
Class<?> stubClass;
try {
// 获取本地存根类
stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
// 检测本地存根类是否可赋值给接口类,若不可赋值则会抛出异常,提醒使用者本地存根类类型不合法
if (!interfaceClass.isAssignableFrom(stubClass)) {
throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
}
}
// 为ApplicationConfig的设置property,从环境变量或配置文件中取dubbo.application.<id>.<property>和dubbo.application.<property>
// 另外还设置dubbo.service.shutdown.wait和dubbo.service.shutdown.wait.seconds参数
checkApplication();
// 如果xml文件中未配置<dubbo:registry address="xxx"/>则从环境变量或配置文件中取dubbo.registry.address
checkRegistry();
// 如果xml文件未配置<dubbo:protocol name="dubbo" port="xxx"/>则从取<dubbo:provider protocol="xxx" />
checkProtocol();
// 为ServiceConfig的设置property,从环境变量或配置文件中取dubbo.service.<id>.<property> 和 dubbo.service.<property>
appendProperties(this);
checkStubAndMock(interfaceClass);
if (path == null || path.length() == 0) {
path = interfaceName;
}
// 导出链接URL
doExportUrls();
ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
}
初始化ApplicationConfig、ProtocolConfig、ServiceConfig等对象,为导出做一些提前的准备工作。
// 导出链接URL
// ServiceConfig#doExportUrls()
private void doExportUrls() {
// 加载注册中心链接
List<URL> registryURLs = loadRegistries(true);
// 遍历protocols,并在每个协议下导出服务
for (ProtocolConfig protocolConfig : protocols) {
// 暴露dubbo服务:<dubbo:protocol name="dubbo" port="20880" id="dubbo" />
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
// 检查是否配置了注册中心 eg. <dubbo:registry address="multicast://224.5.6.7:1234"/>
// 封装URL对象
// 返回注册中心列表
// AbstractInterfaceConfig#loadRegistries(boolean)
protected List<URL> loadRegistries(boolean provider) {
// 如果xml文件中未配置<dubbo:registry address="xxx"/>则从环境变量或配置文件中取dubbo.registry.address
checkRegistry();
List<URL> registryList = new ArrayList<URL>();
if (registries != null && registries.size() > 0) {
for (RegistryConfig config : registries) {
String address = config.getAddress();
// 注册中心地址为空,则设置为0.0.0.0
if (address == null || address.length() == 0) {
address = Constants.ANYHOST_VALUE;
}
// 系统属性中获取注册中心地址
String sysaddress = System.getProperty("dubbo.registry.address");
if (sysaddress != null && sysaddress.length() > 0) {
// 系统环境变量参数dubbo.registry.address会覆盖xml配置文件的注册中心地址
address = sysaddress;
}
if (address != null && address.length() > 0
&& !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
// 把ApplicationConfig、RegistryConfig、path、dubbo、timestamp、pid、protocol等放进map对象中
Map<String, String> map = new HashMap<String, String>();
appendParameters(map, application);
appendParameters(map, config);
map.put("path", RegistryService.class.getName());
map.put("dubbo", Version.getVersion());
map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
if (ConfigUtils.getPid() > 0) {
map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
}
if (!map.containsKey("protocol")) {
if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
map.put("protocol", "remote");
} else {
map.put("protocol", "dubbo");
}
}
// 注册中心地址可能有多个,这里返回一个列表
// 解析注册中心配置地址到URL
List<URL> urls = UrlUtils.parseURLs(address, map);
for (URL url : urls) {
// 添加"registry"="zookeeper"到URL.parameters
url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
// 设置url.protocol="registry"
url = url.setProtocol(Constants.REGISTRY_PROTOCOL);
if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
|| (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
// 添加到注册中心列表中
registryList.add(url);
}
}
}
}
}
return registryList;
}
初始化注册中心信息,并且存放在URL的对象中,以便后期做导出准备。
// 检查配置<dubbo:protocol name="dubbo" port="20886" />为空,默认协议为dubbo和端口20880
// 封装map集合参数,然后封装的URL对象中
// 导出服务到本地/远程
// ServiceConfig#doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs)
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
String name = protocolConfig.getName();
if (name == null || name.length() == 0) {
// 默认协议名为dubbo
name = "dubbo";
}
Map<String, String> map = new HashMap<String, String>();
// "side" -> "provider"
map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);
// "dubbo" -> "2.0.2"
map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());
// "timestamp" -> "1568339911006"
map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
// "pid" -> "13072"
if (ConfigUtils.getPid() > 0) {
map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
}
// "application" -> "demo-provider"
// ...
appendParameters(map, application);
appendParameters(map, module);
appendParameters(map, provider, Constants.DEFAULT_KEY);
appendParameters(map, protocolConfig);
// "interface" -> "com.alibaba.dubbo.demo.DemoService"
// "bean.name" -> "com.alibaba.dubbo.demo.DemoService"
appendParameters(map, this);
if (methods != null && methods.size() > 0) {
// MethodConfig保存了<dubbo:method>的信息
for (MethodConfig method : methods) {
// 添加 MethodConfig 对象的字段信息到 map 中,键 = 方法名.属性名。
// eg. <dubbo:method name="sayHello" retries="2"> => {"sayHello.retries": 2}
appendParameters(map, method, method.getName());
String retryKey = method.getName() + ".retry";
if (map.containsKey(retryKey)) {
String retryValue = map.remove(retryKey);
if ("false".equals(retryValue)) {
map.put(method.getName() + ".retries", "0");
}
}
// 解析<dubbo:argument index="1"/>
// 参考:http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-argument.html
List<ArgumentConfig> arguments = method.getArguments();
if (arguments != null && arguments.size() > 0) {
for (ArgumentConfig argument : arguments) {
// convert argument type
...
}
}
} // end of methods for
}
if (ProtocolUtils.isGeneric(generic)) {
map.put("generic", generic);
map.put("methods", Constants.ANY_VALUE);
} else {
// 获取接口版本<dubbo:service interface="xxxService" version="1.0.0">
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put("revision", revision);
}
// 通过Wrapper#makeWrapper(Class<?>)生成一个Wrapper的实现类Wrapper0,通过Wrapper0取到所有方法名
// TODO 为什么要大费周章,而不是用Method[] methods = c.getMethods();直接获取呢
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
if (methods.length == 0) {
logger.warn("NO method found in service interface " + interfaceClass.getName());
map.put("methods", Constants.ANY_VALUE);
} else {
// 添加所有的方法名到map集合。方法名以逗号分隔
map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
}
}
// 添加token到map集合
if (!ConfigUtils.isEmpty(token)) {
if (ConfigUtils.isDefault(token)) {
map.put("token", UUID.randomUUID().toString());
} else {
map.put("token", token);
}
}
// <dubbo:protocol name="injvm"/> 为本地测试
if ("injvm".equals(protocolConfig.getName())) {
protocolConfig.setRegister(false);
// 不需要监听通知
map.put("notify", "false");
}
String contextPath = protocolConfig.getContextpath();
if ((contextPath == null || contextPath.length() == 0) && provider != null) {
contextPath = provider.getContextpath();
}
// 获取host和port
// 先从环境变量中获取DUBBO_DUBBO_IP_TO_BIND或DUBBO_IP_TO_BIND
// 从<dubbo:protocol />中取host参数
// 从<dubbo:provider />中取host参数
// 以上都获取失败了,则取本机的ip地址(官方推荐不要配置该参数)
String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
// 先从环境变量中获取DUBBO_DUBBO_PORT_TO_BIND或DUBBO_PORT_TO_BIND
// 从<dubbo:protocol />中取host参数
// 从<dubbo:provider />中取host参数
// 以上都获取失败了,则取默认的dubbo服务暴露端口20880(在DubboProtocol.DEFAULT_PORT)
Integer port = this.findConfigedPorts(protocolConfig, name, map);
// 承载dubbo暴露接口配置信息
URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);
// TODO 不知道干嘛的
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.hasExtension(url.getProtocol())) {
url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.getExtension(url.getProtocol()).getConfigurator(url).configure(url);
}
// 获取provider的scope配置 eg. <dubbo:provider scope="local" />
String scope = url.getParameter(Constants.SCOPE_KEY);
// scope == null || scope != "none"
if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {
// (scope == null || scope != "remote") => 导出本地
if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
exportLocal(url);
}
// (scope == null || scope != "local") => 导出远程
if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {
if (logger.isInfoEnabled()) {
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
}
if (registryURLs != null && registryURLs.size() > 0) {
// 遍历注册中心URL
for (URL registryURL : registryURLs) {
url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
// 加载Service监控对象MonitorConfig
// 另有章节详细讲解监控的实现
URL monitorUrl = loadMonitor(registryURL);
if (monitorUrl != null) {
// 添加"monitor":"监控地址"到url.parameters
url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
}
...
// For providers, this is used to enable custom proxy to generate invoker
String proxy = url.getParameter(Constants.PROXY_KEY);
if (StringUtils.isNotEmpty(proxy)) {
// 为注册中心的url.parameters添加参数proxy
registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
}
// 为服务提供类(ref)生成Invoker
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
// 封装invoker和ServiceConfig到DelegateProviderMetaDataInvoker
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
// 导出服务
// 注册中心暴露服务过程:ProtocolFilterWrapper -> ProtocolListenerWrapper -> RegistryProtocol
// dubbo暴露服务过程:ProtocolFilterWrapper -> ProtocolListenerWrapper -> DubboProtocol
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
} else {
// 无注册中心
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
}
}
this.urls.add(url);
}
初始化URL(用于承载Dubbo服务暴露的),并封装各种参数到url.parameters属性中。下面分析一下DubboProtocol和RegistryProtocol的导出服务的过程。
// 导出DelegateProviderMetaDataInvoker
// Exporter<?> exporter = protocol.export(wrapperInvoker);
// DubboProtocol.export(wrapperInvoker);
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
URL url = invoker.getUrl();
// 获取服务标识。由服务组名,服务名,服务版本号以及端口组成。
// eg. demoGroup/com.alibaba.dubbo.demo.DemoService:1.0.1:20880
String key = serviceKey(url);
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
// put到缓存
// Map<String, Exporter<?>> exporterMap
exporterMap.put(key, exporter);
// 从url获取dubbo.stub.event参数
Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);
// 从url获取is_callback_service参数
Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
if (isStubSupportEvent && !isCallbackservice) {
// TODO 暂不深入
String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
...
} else {
stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
}
}
// 启动Netty服务器端
openServer(url);
return exporter;
}
// DubboProtocol#openServer(URL)
private void openServer(URL url) {
// find server.
// eg. 10.0.75.1:20880
String key = url.getAddress();
//client can export a service which's only for server to invoke
boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
if (isServer) {
ExchangeServer server = serverMap.get(key);
if (server == null) {
// 该dubbo协议还没有Netty服务端
// 创建Netty服务端
serverMap.put(key, createServer(url));
} else {
// server supports reset, use together with override
server.reset(url);
}
}
}
// DubboProtocol#createServer(URL url)
private ExchangeServer createServer(URL url) {
// send readonly event when server closes, it's enabled by default
// "channel.readonly.sent" -> "true"
url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());
// enable heartbeat by default
// "heartbeat" -> "60000"
url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
// 获取服务端类型,默认netty
String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER);
if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str))
throw new RpcException("Unsupported server type: " + str + ", url: " + url);
// "codec" -> "dubbo"
url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME);
ExchangeServer server;
try {
//
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
}
str = url.getParameter(Constants.CLIENT_KEY);
if (str != null && str.length() > 0) {
// 是否为支持的服务端类型
Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
if (!supportedTypes.contains(str)) {
throw new RpcException("Unsupported client type: " + str);
}
}
return server;
}
// Exchangers#bind(URL, ExchangeHandler)
public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
...
// 上面设置了"codec" -> "dubbo",因此不会执行下面方法
// CODEC_KEY
url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
// getExchanger(url)默认获得HeaderExchanger实例
return getExchanger(url).bind(url, handler);
}
// HeaderExchanger#bind(URL, ExchangeHandler)
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
// 通过Transporters#bind(URL, ChannelHandler...)获取一个Server实例
// 通过Server实例创建一个HeaderExchangeServer实例
// HeaderExchangeServer使用的是装饰器模式,对NettyServer的增强,增加心跳机制
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}
// Transporters#bind(URL, ChannelHandler...)
public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {
...
ChannelHandler handler;
if (handlers.length == 1) {
handler = handlers[0];
} else {
// ChannelHandlerDispatcher包含Collection<ChannelHandler> channelHandlers,是多个ChannelHandler的封装
handler = new ChannelHandlerDispatcher(handlers);
}
// getTransporter()默认获得NettyTransporter实例
return getTransporter().bind(url, handler);
}
// NettyTransporter#bind(URL, ChannelHandler)
// NettyTransporter负责Netty服务端的绑定、Netty客户端的连接
public Server bind(URL url, ChannelHandler listener) throws RemotingException {
return new NettyServer(url, listener);
}
使用DubboProtocol对暴露dubbo服务。初始化Netty服务端,开启Netty服务,对外提供Netty服务。关于Netty如何解码编码暂不做详细分析。
接下来,分析一下RegistryProtocol是如何把服务注册到注册中心的。
// 导出DelegateProviderMetaDataInvoker
// Exporter<?> exporter = protocol.export(wrapperInvoker);
// RegistryProtocol.export(wrapperInvoker)
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
...
boolean register = registeredProviderUrl.getParameter("register", true);
if (register) {
// 注册服务
register(registryUrl, registedProviderUrl);
ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
}
...
}
public void register(URL registryUrl, URL registedProviderUrl) {
// 创建注册中心
// ZookeeperRegistryFactory.createRegistry(URL url)
Registry registry = registryFactory.getRegistry(registryUrl);
// 注册服务
// FailbackRegistry.register(URL url)
registry.register(registedProviderUrl);
}
// 创建注册中心
// ZookeeperRegistryFactory.createRegistry(URL url)
public Registry createRegistry(URL url) {
return new ZookeeperRegistry(url, zookeeperTransporter);
}
// ZookeeperRegistry的构造方法
public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
super(url);
if (url.isAnyHost()) {
throw new IllegalStateException("registry address == null");
}
// 获取组名,默认为 dubbo
String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
if (!group.startsWith(Constants.PATH_SEPARATOR)) {
// group = "/" + group
group = Constants.PATH_SEPARATOR + group;
}
this.root = group;
// 创建 Zookeeper 客户端,默认为 CuratorZookeeperTransporter
zkClient = zookeeperTransporter.connect(url);
// 添加状态监听器
zkClient.addStateListener(new StateListener() {
public void stateChanged(int state) {
if (state == RECONNECTED) {
try {
recover();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
});
}
// 注册服务
// FailbackRegistry.register(URL url)
public void register(URL url) {
if (destroyed.get()){
return;
}
super.register(url);
failedRegistered.remove(url);
failedUnregistered.remove(url);
try {
// 调用注册中心注册
// 以Zookeeper为例分析
// ZookeeperRegistry.doRegister(URL url)
doRegister(url);
} catch (Exception e) {
...
}
}
// Zookeeper注册中心注册
// ZookeeperRegistry.doRegister(URL url)
protected void doRegister(URL url) {
try {
zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
} catch (Throwable e) {
...
}
}
Zookeeper通过创建节点保存服务提供者信息,暴露服务。