三Dubbo服务暴露源码分析--3远程暴露-下
三Dubbo服务暴露源码分析--3远程暴露-下
//PTC2.2.2 DubboProtocol.serverMap.put(key, createServer(url))
DubboProtocol
private final Map<String, ExchangeServer> serverMap = new ConcurrentHashMap<String, ExchangeServer>(); // <host:port,Exchanger>
private void openServer(URL url) {
//192.168.0.101:20880
String key = url.getAddress();
//client 也可以暴露一个只有server可以调用的服务。
boolean isServer = url.getParameter(Constants.IS_SERVER_KEY,true);
if (isServer) {
ExchangeServer server = serverMap.get(key);
if (server == null) {
//PTC2.2.1 createServer 创建ExchangeServer
//PTC2.2.2 DubboProtocol.serverMap.put(key, createServer(url))
serverMap.put(key, createServer(url));
} else {
//server支持reset,配合override功能使用
server.reset(url);
}
}
}
在//PTC2.2.1 createServer 创建ExchangeServer,返回HeaderExchangeServer后,会将其存入serverMap中。
此时,在DubboProtocol中有两个map,分别存储exchangeServer的服务端,和暴露的服务dubboExporter。
//EXP3.1.4 ExporterChangeableWrapper
然后,回到这里
RegistryProtocol
//本地缓存,记录providerURL暴露的exporter服务--避免暴露过的服务,不再重新暴露
private final Map<String, ExporterChangeableWrapper<?>> bounds = new ConcurrentHashMap<String, ExporterChangeableWrapper<?>>();
private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker){
//EXP3.1.1 getCacheKey(获取invoker在bounds中缓存的key)
String key = getCacheKey(originInvoker);
//然后获取bounds内缓存的exporter---避免重复暴露
ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
/**………………………………………………………………RegistryProtocol中bounds,记录是否暴露过服务………………………………………………………………………………………… */
if (exporter == null) {
synchronized (bounds) {//加锁
exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
if (exporter == null) {
//EXP3.1.2 InvokerDelegete
final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));
//EXP3.1.3 protocol.export
//EXP3.1.4 ExporterChangeableWrapper
exporter = new ExporterChangeableWrapper<T>((Exporter<T>)protocol.export(invokerDelegete), originInvoker);
bounds.put(key, exporter);
}
}
}
return (ExporterChangeableWrapper<T>) exporter;
}
在//EXP3.1.3 protocol.export中暴露的exporter
然后,此处创建的ExporterChangeableWrapper,是在protocol.export暴露服务exporter成功后,创建exporter的代理类,用来建立originInvoker与protocol.export出的exporter的对应关系。在override时候,可以进行关系修改。
RegistryProtocol的内部类
private class ExporterChangeableWrapper<T> implements Exporter<T>{
//绑定origin与根据该originInvoker暴露出服务exporter的对应关系,在override协议进行change时,修改对应关系
private Exporter<T> exporter;
private final Invoker<T> originInvoker;
public ExporterChangeableWrapper(Exporter<T> exporter, Invoker<T> originInvoker){
this.exporter = exporter;
this.originInvoker = originInvoker;
}
public Invoker<T> getOriginInvoker() {
return originInvoker;
}
//
public Invoker<T> getInvoker() {
return exporter.getInvoker();
}
其中,originInvoker为注册服务registry://的invoker,exporter为被listenerwrapper包过的DubboExporter。
在RegistryProtocol中的bounds,记录providerurl与暴露出的服务exporter,避免被重复暴露。
//用于解决rmi重复暴露端口冲突的问题,已经暴露过的服务不再重新暴露
//providerurl <--> exporter
private final Map<String, ExporterChangeableWrapper<?>> bounds = new ConcurrentHashMap<String, ExporterChangeableWrapper<?>>();
/** …………向注册中心注册服务…………………………*/
RegistryProtocol
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
//EXP3.1 doLocalExport
//对服务dubbo://的暴露,并打开端口等操作
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
//EXP3.2 getRegistry
//根据originInvoker的注册中心zookeeper://,加载registryService的实现类--zookeeperRegistry
final Registry registry = getRegistry(originInvoker);
//获取注册的服务提供者的URL,即dubbo://
final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
//EXP3.3 registry.register
//将provider信息,注册到注册中心
registry.register(registedProviderUrl);
/**…………………………………………………………………………………………………………override信息、overrideListener的订阅……………………………………………………………………………… */
// 订阅override数据
// FIXME 提供者订阅时,会影响同一JVM即暴露服务,又引用同一服务的的场景,因为subscribed以服务名为缓存的key,导致订阅信息覆盖。
//获取订阅的override数据
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
//创建override监听器
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
//向注册中心订阅override
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
//保证每次export都返回一个新的exporter实例(其包裹的exporter是EXP3.1doLocalExport中暴露的服务exporter)
return new Exporter<T>() {
public Invoker<T> getInvoker() {
return exporter.getInvoker();
}
public void unexport() {
try {
exporter.unexport();
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
try {
registry.unregister(registedProviderUrl);
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
try {
overrideListeners.remove(overrideSubscribeUrl);
registry.unsubscribe(overrideSubscribeUrl, overrideSubscribeListener);
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
}
};
}
EXP3.2 getRegistry--创建zookeeperRegistry
//EXP3.2 getRegistry
//根据originInvoker的注册中心zookeeper://,加载registryService的实现类--zookeeperRegistry
final Registry registry = getRegistry(originInvoker);
//获取注册的服务提供者的URL,即dubbo://
final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
//EXP3.3 registry.register
//将provider信息,注册到注册中心
registry.register(registedProviderUrl);
此时,originInvoker实例,是registry://localhost:2181,向注册中心registry注册。
RegistryProtocol
private Registry getRegistry(final Invoker<?> originInvoker){
//registry://localhost:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-provider&dubbo=2.5.3&export=dubbo%3A%2F%2F192.168.0.101%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemotest-provider%26dubbo%3D2.5.3%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DgetPermissions%26organization%3Ddubbox%26owner%3Dprogrammer%26pid%3D89785%26side%3Dprovider%26timestamp%3D1671504677853&organization=dubbox&owner=programmer&pid=89785®istry=zookeeper×tamp=1671504677724
URL registryUrl = originInvoker.getUrl();
if (Constants.REGISTRY_PROTOCOL.equals(registryUrl.getProtocol())) {
//registry注册中心协议为zookeeper
String protocol = registryUrl.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_DIRECTORY);
//将注册URL协议头更换为zookeeper
registryUrl = registryUrl.setProtocol(protocol).removeParameter(Constants.REGISTRY_KEY);
}
//EXP3.2.1 RegistryFactory$Adpative.getRegistry
return registryFactory.getRegistry(registryUrl);
}
上述过程,将registryURL的registry://协议头,更换为zookeeper://,并从registryFactory工厂类中获取zookeeperRegistry注册中心。
//EXP3.2.1 RegistryFactory$Adpative.getRegistry
public class RegistryFactory$Adpative implements com.alibaba.dubbo.registry.RegistryFactory {
public com.alibaba.dubbo.registry.Registry getRegistry(com.alibaba.dubbo.common.URL arg0) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg0;
//zookeeper
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.registry.RegistryFactory) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.registry.RegistryFactory extension = (com.alibaba.dubbo.registry.RegistryFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.registry.RegistryFactory.class).getExtension(extName);
//extension为zookeeperRegistryFactory
return extension.getRegistry(arg0);
}
}
AbstractRegistryFactory
public Registry getRegistry(URL url) {
//将registryurl的parameter参数对中export部分(保存dubbo://编码值)删除,然后向其中添加interface为RegistryService
url = url.setPath(RegistryService.class.getName())
.addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
.removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
//zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService
String key = url.toServiceString();
// 锁定注册中心获取过程,保证注册中心单一实例
LOCK.lock();
try {
Registry registry = REGISTRIES.get(key);
if (registry != null) {
return registry;
}
/**………………………………………………………………………………………………创建zookeeperRegistry注册中心………………………………………………………………………………………………………… */
//EXP3.2.1.1 createRegistry
registry = createRegistry(url);
if (registry == null) {
throw new IllegalStateException("Can not create registry " + url);
}
//将注册中心放入缓存
REGISTRIES.put(key, registry);
return registry;
} finally {
// 释放锁
LOCK.unlock();
}
}
//EXP3.2.1.1 createRegistry
createRegistry由子类实现。
public class ZookeeperRegistryFactory extends AbstractRegistryFactory {
//dubbo的@SPI自动注入
private ZookeeperTransporter zookeeperTransporter;
public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) {
this.zookeeperTransporter = zookeeperTransporter;
}
public Registry createRegistry(URL url) {
//ZKR ZookeeperRegistry
return new ZookeeperRegistry(url, zookeeperTransporter);
}
}
//ZKR ZookeeperRegistry初始化
ZookeeperRegistry实现与zookeeper注册中心的交互逻辑。
public class ZookeeperRegistry extends FailbackRegistry {
//配置zookeeper客户端端口和根路径
private final static int DEFAULT_ZOOKEEPER_PORT = 2181;
private final static String DEFAULT_ROOT = "dubbo";
//zookeeper上配置的监听器NotifyListener、ChildListener
private final ConcurrentMap<URL, ConcurrentMap<NotifyListener, ChildListener>> zkListeners = new ConcurrentHashMap<URL, ConcurrentMap<NotifyListener, ChildListener>>();
private final ZookeeperClient zkClient;
public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
//zookeeper://localhost:2181……………………
//ZKR1 FailbackRegistry
super(url);
if (url.isAnyHost()) {
throw new IllegalStateException("registry address == null");
}
//group值为dubbo
String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
if (! group.startsWith(Constants.PATH_SEPARATOR)) {
group = Constants.PATH_SEPARATOR + group;
}
//设置zookeeper存储中的根路径=/dubbo
this.root = group;
//ZKR2 zookeeperTransporter$Adpative.connect(url) 连接并创建zkclient
zkClient = zookeeperTransporter.connect(url);
//ZKR3 zkClient.addStateListener 添加监听器
zkClient.addStateListener(new StateListener() { //2
public void stateChanged(int state) { //3
if (state == RECONNECTED) { //4
try {
recover();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}//4
} //3
}); //2
}
//ZKR1 FailbackRegistry--失败重试
FailbackRegistry实现失败重试功能。
// 失败重试定时器,定时检查是否有请求失败,如有,无限次重试
private final ScheduledFuture<?> retryFuture;
/**……………………………………………………………………………………失败操作的集合………………………………………………………………………………………………………… */
private final Set<URL> failedRegistered = new ConcurrentHashSet<URL>();//注册失败
private final Set<URL> failedUnregistered = new ConcurrentHashSet<URL>();//取消注册失败
private final ConcurrentMap<URL, Set<NotifyListener>> failedSubscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>();//订阅失败
private final ConcurrentMap<URL, Set<NotifyListener>> failedUnsubscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>();//取消订阅失败
private final ConcurrentMap<URL, Map<NotifyListener, List<URL>>> failedNotified = new ConcurrentHashMap<URL, Map<NotifyListener, List<URL>>>();//通知失败
public FailbackRegistry(URL url) {
//ZKR1.1 AbstractRegistry
super(url);
int retryPeriod = url.getParameter(Constants.REGISTRY_RETRY_PERIOD_KEY, Constants.DEFAULT_REGISTRY_RETRY_PERIOD);
//failback的registry,使用定时线程池ScheduledExecutorService,定时执行重试retry连接注册中心
this.retryFuture = retryExecutor.scheduleWithFixedDelay(new Runnable() {
public void run() {
// 检测并连接注册中心
try {
/**………………………………………………………………失败重试中,根据失败操作集合中,遍历各个集合,如果有就重新操作……………………………………………………………………………… */
retry();
} catch (Throwable t) { // 防御性容错
logger.error("Unexpected error occur at failed retry, cause: " + t.getMessage(), t);
}
}
}, retryPeriod, retryPeriod, TimeUnit.MILLISECONDS);
}
//ZKR1.1 AbstractRegistry--缓存
AbstractRegistry实现缓存机制。有内存服务缓存、磁盘文件缓存。
Registry实现需要实现缓存的原因:
1 consumer调用服务,如果每次都要从注册中心实时查询可用服务列表,会增大注册中心的处理压力,其次会增加额外的网络请求,会使系统性能下降;
2 使系统不强依赖于注册中心,就是在注册中心宕机时,仍旧能正常的调用服务。
因此,在AbstractRegistry中提供了连个缓存的服务------内存缓存服务、磁盘文件缓存(注册中心重启,会是内存缓存消失,因此再增加文件缓存)。
/**……………………………………………………………………………………………………磁盘文件缓存…………………………………………………………………………………………………………………………………… */
// 本地磁盘缓存文件
private File file;
// 本地磁盘缓存文件的缓存对象,在初始化时,file中数据读入properties中,后续写入,也先写入该properties中,在定时写入file文件中
//key(服务接口名称):value(服务url列表)
private final Properties properties = new Properties();
/**……………………………………………………………………………………………………内存服务缓存…………………………………………………………………………………………………………………………………… */
private final ConcurrentMap<URL, Map<String, List<URL>>> notified = new ConcurrentHashMap<URL, Map<String, List<URL>>>();
//存储的内容为(zookeeper://,map(providers/routers/configurators/consumers,List(服务URL) ) )
//URL为注册中心的地址
注意缓存文件的写入时机。
//registry中保存当前注册中心的地址
//zookeeper://localhost:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-provider&dubbo=2.5.3&interface=com.alibaba.dubbo.registry.RegistryService&organization=dubbox&owner=programmer&pid=90630×tamp=1671506059060
private URL registryUrl;
/**……………………………………………………………………………………………………磁盘文件缓存…………………………………………………………………………………………………………………………………… */
// 本地磁盘缓存文件
private File file;
// 本地磁盘缓存,其中特殊的key值.registies记录注册中心列表,其它均为notified服务提供者列表
private final Properties properties = new Properties();
// 文件缓存定时写入的线程
private final ExecutorService registryCacheExecutor = Executors.newFixedThreadPool(1, new NamedThreadFactory("DubboSaveRegistryCache", true));
//是否是同步保存文件
private final boolean syncSaveFile ;
/**……………………………………………………………………………………………………内存服务缓存…………………………………………………………………………………………………………………………………… */
private final ConcurrentMap<URL, Map<String, List<URL>>> notified = new ConcurrentHashMap<URL, Map<String, List<URL>>>();
private final AtomicLong lastCacheChanged = new AtomicLong();
private final Set<URL> registered = new ConcurrentHashSet<URL>();
//订阅url的notifyListener的set集合
private final ConcurrentMap<URL, Set<NotifyListener>> subscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>();
//初始化
public AbstractRegistry(URL url) {
setUrl(url);
// 启动文件保存定时器
syncSaveFile = url.getParameter(Constants.REGISTRY_FILESAVE_SYNC_KEY, false);
//本地缓存文件的全路径名称:/Users/app/.dubbo/dubbo-registry-localhost.cache
String filename = url.getParameter(Constants.FILE_KEY, System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getHost() + ".cache");
File file = null;
//创建本地缓存文件
if (ConfigUtils.isNotEmpty(filename)) {
file = new File(filename);
if(! file.exists() && file.getParentFile() != null && ! file.getParentFile().exists()){
if(! file.getParentFile().mkdirs()){
throw new IllegalArgumentException("Invalid registry store file " + file + ", cause: Failed to create directory " + file.getParentFile() + "!");
}
}
}
this.file = file;
//ZKR1.1.1 loadProperties
loadProperties();
//ZKR1.1.2 AbstractRegistry.notify
notify(url.getBackupUrls());
}
AbstractRegistry的初始化过程中,负责创建缓存文件(内存缓存和文件缓存),并将文件缓存加载到当前类的properteis的键值对对象中。
//ZKR1.1.1 loadProperties
加载文件缓存内容到properties的键值对对象中。
private void loadProperties() {
if (file != null && file.exists()) {
InputStream in = null;
try {
in = new FileInputStream(file);
//加载入properties
properties.load(in);
if (logger.isInfoEnabled()) {
logger.info("Load registry store file " + file + ", data: " + properties);
}
} catch (Throwable e) {
logger.warn("Failed to load registry store file " + file, e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
logger.warn(e.getMessage(), e);
}
}
}
}
}
//ZKR1.1.2 AbstractRegistry.notify---???consumer端???
这里不执行通知(consumer端,在订阅时候,会在AbstractRegistry中注册NotifyListener,并加入subscribed中)
protected void notify(List<URL> urls) {
if(urls == null || urls.isEmpty()) return;
//遍历 private final ConcurrentMap<URL, Set<NotifyListener>> subscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>(); 这里是保存url与订阅关注该url的notifyListener监听器的set集合
//这里尚未添加NotifyListener通知监听器,所以不处理
for (Map.Entry<URL, Set<NotifyListener>> entry : getSubscribed().entrySet()) {
URL url = entry.getKey();//被关注的url
//传入的url匹配,看是否与abstractRegistry中保存的url匹配、相同
if(! UrlUtils.isMatch(url, urls.get(0))) {
continue;
}
Set<NotifyListener> listeners = entry.getValue();
if (listeners != null) {
for (NotifyListener listener : listeners) {
try {
//通知
notify(url, listener, filterEmpty(url, urls));
} catch (Throwable t) {
logger.error("Failed to notify registry event, urls: " + urls + ", cause: " + t.getMessage(), t);
}
}
}
}
}
//ZKR2 zookeeperTransporter$Adpative.connect(url) 连接并创建zkclient
public class ZookeeperTransporter$Adpative implements com.alibaba.dubbo.remoting.zookeeper.ZookeeperTransporter {
public com.alibaba.dubbo.remoting.zookeeper.ZookeeperClient connect(com.alibaba.dubbo.common.URL arg0) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg0;
//客户端为zkclient
String extName = url.getParameter("client", url.getParameter("transporter", "zkclient"));
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.remoting.zookeeper.ZookeeperTransporter) name from url(" + url.toString() + ") use keys([client, transporter])");
com.alibaba.dubbo.remoting.zookeeper.ZookeeperTransporter extension = (com.alibaba.dubbo.remoting.zookeeper.ZookeeperTransporter)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.remoting.zookeeper.ZookeeperTransporter.class).getExtension(extName);
//ZkclientZookeeperTransporter
return extension.connect(arg0);
}
public class ZkclientZookeeperTransporter implements ZookeeperTransporter {
public ZookeeperClient connect(URL url) {
//ZKR2.1 ZkclientZookeeperClient
return new ZkclientZookeeperClient(url);
}
//ZKR2.1 ZkclientZookeeperClient初始化
public ZkclientZookeeperClient(URL url) {
//zookeeper://localhost:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-provider&dubbo=2.5.3&interface=com.alibaba.dubbo.registry.RegistryService&organization=dubbox&owner=programmer&pid=2163×tamp=1671526419537
super(url);
//ZKR2.1.1 ZkClient
//localhost:2181,客户端连接
client = new ZkClient(url.getBackupAddress());
//ZKR2.1.2 client.subscribeStateChanges
client.subscribeStateChanges(new IZkStateListener() {
public void handleStateChanged(KeeperState state) throws Exception {
ZkclientZookeeperClient.this.state = state;
if (state == KeeperState.Disconnected) {
stateChanged(StateListener.DISCONNECTED);
} else if (state == KeeperState.SyncConnected) {
stateChanged(StateListener.CONNECTED);
}
}
public void handleNewSession() throws Exception {
stateChanged(StateListener.RECONNECTED);
}
});
}
//ZKR2.1.1 ZkClient--连接zk并设置当前zkclient为watcher
public ZkClient(final IZkConnection zkConnection, final int connectionTimeout, final ZkSerializer zkSerializer, final long operationRetryTimeout) {
if (zkConnection == null) {
throw new NullPointerException("Zookeeper connection is null!");
}
_connection = zkConnection;
_zkSerializer = zkSerializer;
_operationRetryTimeoutInMillis = operationRetryTimeout;
_isZkSaslEnabled = isZkSaslEnabled();
//连接zkserver,并将当前zkclient当做watcher
connect(connectionTimeout, this);
}
public void connect(final long maxMsToWaitUntilConnected, Watcher watcher) throws ZkInterruptedException, ZkTimeoutException, IllegalStateException {
boolean started = false;
acquireEventLock();
try {
setShutdownTrigger(false);
_eventThread = new ZkEventThread(_connection.getServers());
_eventThread.start();
//zk客户端连接zkserver
_connection.connect(watcher);
LOG.debug("Awaiting connection to Zookeeper server");
boolean waitSuccessful = waitUntilConnected(maxMsToWaitUntilConnected, TimeUnit.MILLISECONDS);
if (!waitSuccessful) {
throw new ZkTimeoutException("Unable to connect to zookeeper server '" + _connection.getServers() + "' with timeout of " + maxMsToWaitUntilConnected + " ms");
}
started = true;
} finally {
getEventLock().unlock();
// we should close the zookeeper instance, otherwise it would keep
// on trying to connect
if (!started) {
close();
}
}
}
@Override
public void connect(Watcher watcher) {
_zookeeperLock.lock();
try {
if (_zk != null) {
throw new IllegalStateException("zk client has already been started");
}
try {
LOG.debug("Creating new ZookKeeper instance to connect to " + _servers + ".");
//创建zookeeper,在初始化中,执行this.cnxn.start(),打开zookeeper的客户端连接zkserver
_zk = new ZooKeeper(_servers, _sessionTimeOut, watcher);
} catch (IOException e) {
throw new ZkException("Unable to connect to " + _servers, e);
}
} finally {
_zookeeperLock.unlock();
}
}
//ZKR2.1.2 client.subscribeStateChanges
public ZkclientZookeeperClient(URL url) {
//ZKR2.1.1 ZkClient
//localhost:2181,客户端连接
client = new ZkClient(url.getBackupAddress());
//ZKR2.1.2 client.subscribeStateChanges
client.subscribeStateChanges(new IZkStateListener() {
//这个监听器,监听zkclient客户单的连接状态
public void handleStateChanged(KeeperState state) throws Exception {
ZkclientZookeeperClient.this.state = state;
if (state == KeeperState.Disconnected) {
stateChanged(StateListener.DISCONNECTED);
} else if (state == KeeperState.SyncConnected) {
stateChanged(StateListener.CONNECTED);
}
}
public void handleNewSession() throws Exception {
stateChanged(StateListener.RECONNECTED);
}
});
//ZKR3 zkClient.addStateListener 添加监听器
返回到ZookeeperRegistry的初始化过程。
public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
//zookeeper://localhost:2181……………………
//ZKR1 FailbackRegistry
super(url);
if (url.isAnyHost()) {
throw new IllegalStateException("registry address == null");
}
//group值为dubbo
String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
if (! group.startsWith(Constants.PATH_SEPARATOR)) {
group = Constants.PATH_SEPARATOR + group;
}
//设置zookeeper存储中的根路径=/dubbo
this.root = group;
//ZKR2 zookeeperTransporter$Adpative.connect(url) 连接并创建zkclient
zkClient = zookeeperTransporter.connect(url);
//ZKR3 zkClient.addStateListener 添加监听器
zkClient.addStateListener(new StateListener() { //2
public void stateChanged(int state) { //3
if (state == RECONNECTED) { //4
try {
recover();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}//4
} //3
}); //2
}
此时,返回的zkclient如下:
然后,对zk客户端,添加重新连接的状态监听。在重新连接时,把recoverd的加入失败队列failedRegistered、FailedSubscribed。
EXP3.3 registry.register
回到EXP3 RegistryProtocol.export的过程
RegistryProtocol
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
//EXP3.1 doLocalExport
//对服务dubbo://的暴露,并打开端口等操作
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
//EXP3.2 getRegistry
//根据originInvoker的注册中心zookeeper://,加载registryService的实现类--zookeeperRegistry
final Registry registry = getRegistry(originInvoker);
//获取注册的服务提供者的URL,即dubbo://
final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
//EXP3.3 registry.register
//将provider信息,注册到注册中心
registry.register(registedProviderUrl);
/**…………………………………………………………………………………………………………override信息、overrideListener的订阅………????……………………………………………………………………… */
// 订阅override数据
// FIXME 提供者订阅时,会影响同一JVM即暴露服务,又引用同一服务的的场景,因为subscribed以服务名为缓存的key,导致订阅信息覆盖。
//获取订阅的override数据
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
//创建override监听器
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
//向注册中心订阅override
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
/**…………………………………………从RegistryProtocol返回Exporter匿名类………………………………………… */
//保证每次export都返回一个新的exporter实例(其包裹的exporter是EXP3.1doLocalExport中暴露的服务exporter)
return new Exporter<T>() {
public Invoker<T> getInvoker() {
return exporter.getInvoker();
}
public void unexport() {
try {
exporter.unexport();
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
try {
registry.unregister(registedProviderUrl);
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
try {
overrideListeners.remove(overrideSubscribeUrl);
registry.unsubscribe(overrideSubscribeUrl, overrideSubscribeListener);
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
}
};
}
然后,从originInvoker中获取要注册的服务providerURL
originInvoker的url如下:
registry://localhost:2181/com.alibaba.dubbo.registry.RegistryService?application=demotest-provider&dubbo=2.5.3&export=dubbo%3A%2F%2F192.168.0.101%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemotest-provider%26dubbo%3D2.5.3%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DgetPermissions%26organization%3Ddubbox%26owner%3Dprogrammer%26pid%3D2163%26side%3Dprovider%26timestamp%3D1671526419741&organization=dubbox&owner=programmer&pid=2163®istry=zookeeper×tamp=1671526419537
在originInvoker中仍旧存有export=…………要暴露的服务。
//从originInvoker中获取注册的服务提供者的URL,即dubbo://,该url就是要注册到zookeeper上的服务
final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
//EXP3.3 registry.register
//将provider信息,注册到注册中心
registry.register(registedProviderUrl);
FailbackRegistry
public void register(URL url) {
//EXP3.3.1 AbstractRegistry.register
super.register(url);
//可能是重试过程的register,因此需要删除注册、取消注册失败的任务URL
failedRegistered.remove(url);
failedUnregistered.remove(url);
try {
//EXP3.3.2 ZookeeperRegistry.doRegister
// 向服务器端发送注册请求---由子类zookeeperRegistry实现逻辑
doRegister(url);
} catch (Exception e) {
Throwable t = e;
// 如果开启了启动时检测,则直接抛出异常
boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)
&& url.getParameter(Constants.CHECK_KEY, true)
&& ! Constants.CONSUMER_PROTOCOL.equals(url.getProtocol());
boolean skipFailback = t instanceof SkipFailbackWrapperException;
if (check || skipFailback) {
if(skipFailback) {
t = t.getCause();
}
throw new IllegalStateException("Failed to register " + url + " to registry " + getUrl().getAddress() + ", cause: " + t.getMessage(), t);
} else {
logger.error("Failed to register " + url + ", waiting for retry, cause: " + t.getMessage(), t);
}
// 将失败的注册请求记录到失败列表,定时重试
failedRegistered.add(url);
}
}
EXP3.3.1 AbstractRegistry.register
//记录注册过的服务URL
private final Set<URL> registered = new ConcurrentHashSet<URL>();
public void register(URL url) {
if (url == null) {
throw new IllegalArgumentException("register url == null");
}
if (logger.isInfoEnabled()){
logger.info("Register: " + url);
}
registered.add(url);
}
EXP3.3.2 ZookeeperRegistry.doRegister
ZookeeperRegistry
protected void doRegister(URL url) {
try {
//利用zkclient创建节点;第二个参数,是否创建临时节点,默认为true(providerurl临时节点,会再服务下线时自动删除)
zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
} catch (Throwable e) {
throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
这里是拼接providerURL在zookeeper中注册的完全路径名。
//将providerURL转换为path
private String toUrlPath(URL url) {
//URL.encode(url.toFullString()将dubbo://编码
return toCategoryPath(url) + Constants.PATH_SEPARATOR + URL.encode(url.toFullString());
}
//将providerURL转换为带category的path路径(zookeeper上存储的路径)
private String toCategoryPath(URL url) {
//servicePath/category(provider端默认为provider)
return toServicePath(url) + Constants.PATH_SEPARATOR + url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
}
private String toServicePath(URL url) {
String name = url.getServiceInterface();
if (Constants.ANY_VALUE.equals(name)) {
return toRootPath();
}
return toRootDir() + URL.encode(name);
}
在zookeeper上注册的完整路径如下,provider端的注册,只向category=providers注册。
/dubbo/com.alibaba.dubbo.demo.DemoService/providers/dubbo%3A%2F%2F192.168.0.101%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemotest-provider%26dubbo%3D2.5.3%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DgetPermissions%26organization%3Ddubbox%26owner%3Dprogrammer%26pid%3D2163%26side%3Dprovider%26timestamp%3D1671526419741
然后,在zkclient客户端中创建节点
AbstractZookeeperClient
public void create(String path, boolean ephemeral) {
int i = path.lastIndexOf('/');
if (i > 0) {
//递归创建路径上的父节点
create(path.substring(0, i), false);
}
//创建临时节点
if (ephemeral) {
createEphemeral(path);
} else {
createPersistent(path);
}
}
后续过程省略,此处完成了provider端服务的暴露。