上一篇我们分析了本地暴露,这一篇接着分析远程暴露
定位到ServiceConfig#doExportUrlsFor1Protocol
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
Exporter<?> exporter = protocol.export(invoker);
exporters.add(exporter);
主要分析这三句话
第一句话和上一篇得本地暴露一样,封装一个invoker对象
protocol依然是一个Protocol$Adaptive,
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
这里的extName=registry
当然,这个extension=ProtocolFilterWrapper,而成员变量为ProtocolListenerWrapper
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}
这里就进入if条件
ProtocolListenerWrapper中的成员变量为RegistryListener
进入RegistryListener#export
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);进入
exporter = new ExporterChangeableWrapper<T>((Exporter<T>)protocol.export(invokerDelegete), originInvoker);
这个protocol依然是Protocol$Adaptive
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
而这句话中的extName=dubbo
这边的extension=ProtocolFilterWrapper,而成员变量为ProtocolListenerWrapper
ProtocolListenerWrapper得成员变量为DubboProtocol
同样看到
ProtocolListenerWrapper中的
return new ListenerExporterWrapper<T>(protocol.export(invoker),
Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
.getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
protocol.export(invoker)
进入DubboProtocol#export
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
URL url = invoker.getUrl();
// export service.
String key = serviceKey(url);
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
exporterMap.put(key, exporter);
//export an stub service for dispaching event
Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY,Constants.DEFAULT_STUB_EVENT);
Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
if (isStubSupportEvent && !isCallbackservice){
String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
if (stubServiceMethods == null || stubServiceMethods.length() == 0 ){
if (logger.isWarnEnabled()){
logger.warn(new IllegalStateException("consumer [" +url.getParameter(Constants.INTERFACE_KEY) +
"], has set stubproxy support event ,but no stub methods founded."));
}
} else {
stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
}
}
openServer(url);
return exporter;
}
首先封装一个 DubboExporter
注入传入得invoker对象已经是含有fitler得了
然后把serviceKey(url);获取到的对象作为key,dubboExpoter作为value丢到
exporterMap中
中间略过
openServer(url);这句话很关键,这里将要打开netty通信,关于netty相关的应用,我会在以后的技术文章里面接着更新
createServer(url))注意到这句话
进入后找到
server = Exchangers.bind(url, requestHandler);这行代码
return getExchanger(url).bind(url, handler);
getExchanger返回的是一个Extension对象
(Exchanger)ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type);
这里会返回一个HeaderExchanger,看这个类的bind方法
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeServer(Transporters.bind(url, new ChannelHandler[]{new DecodeHandler(new HeaderExchangeHandler(handler))}));
}
Transporters#bind方法
public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {
。。。。。。
return getTransporter().bind(url, (ChannelHandler)handler);
。。。。。
}
public static Transporter getTransporter() {
return (Transporter)ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension();
}
会返回一个Transporter$Adaptive,拷贝出这个类的bind方法
public com.alibaba.dubbo.remoting.Server bind(com.alibaba.dubbo.common.URL arg0, com.alibaba.dubbo.remoting.ChannelHandler arg1) throws com.alibaba.dubbo.common.URL {
if (arg0 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg0;
String extName = url.getParameter("server", url.getParameter("transporter", "netty"));
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.remoting.Transporter) name from url(" + url.toString() + ") use keys([server, transporter])");
com.alibaba.dubbo.remoting.Transporter extension = (com.alibaba.dubbo.remoting.Transporter)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.remoting.Transporter.class).getExtension(extName);
return extension.bind(arg0, arg1);
}
}
extName=netty 所以extension是NettyTransporter。直接进入NettyTransporter的bind方法
public Server bind(URL url, ChannelHandler listener) throws RemotingException {
return new NettyServer(url, listener);
}
可以看到这里返回了一个NettyServer的实例
在netty的super类AbstractServer的构造函数中我们看到了
this.doOpen();
protected void doOpen() throws Throwable {
NettyHelper.setNettyLoggerFactory();
ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, this.getUrl().getPositiveParameter("iothreads", Constants.DEFAULT_IO_THREADS));
this.bootstrap = new ServerBootstrap(channelFactory);
final NettyHandler nettyHandler = new NettyHandler(this.getUrl(), this);
this.channels = nettyHandler.getChannels();
this.bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
NettyCodecAdapter adapter = new NettyCodecAdapter(NettyServer.this.getCodec(), NettyServer.this.getUrl(), NettyServer.this);
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", adapter.getDecoder());
pipeline.addLast("encoder", adapter.getEncoder());
pipeline.addLast("handler", nettyHandler);
return pipeline;
}
});
this.channel = this.bootstrap.bind(this.getBindAddress());
}
这一串就是netty的启动方式,关于netty的应用会在后续文章中提及
回到HeaderExchanger
所以这句代码实际返回的是一个NettyServer
Transporters.bind(url, new ChannelHandler[]{new DecodeHandler(new HeaderExchangeHandler(handler))})
进入HeaderExchangeServer的构造函数
public HeaderExchangeServer(Server server) {
if (server == null) {
throw new IllegalArgumentException("server == null");
} else {
this.server = server;
this.heartbeat = server.getUrl().getParameter("heartbeat", 0);
this.heartbeatTimeout = server.getUrl().getParameter("heartbeat.timeout", this.heartbeat * 3);
if (this.heartbeatTimeout < this.heartbeat * 2) {
throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2");
} else {
this.startHeatbeatTimer();
}
}
}
这个构造函数中主要是做了心跳检测的定时器
回到DubboProtocol#openServer
this.serverMap.put(key, this.createServer(url));
以ip端口号为key,刚刚生成的HeaderExchangeServer为value加入到serverMap中
回到ProtocolListenerWrapper中
new ListenerExporterWrapper(this.protocol.export(invoker), Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class).getActivateExtension(invoker.getUrl(), "exporter.listener"))));
这个ListnerExporeterWrapper是一个成员变量是一个DubboExtproter,listner的对象
回到ResgistryProtocol#doLocalExport方法
exporter = new ExporterChangeableWrapper<T>((Exporter<T>)protocol.export(invokerDelegete), originInvoker);
bounds.put(key, exporter);
}
}
}
return (ExporterChangeableWrapper<T>) exporter;
这里吧刚刚返回的ListnerExporeterWrapper封装到了一个ExporterChangeableWrapper,并放到了bounds中缓存起来,然后返回到
ResgistryProtocol#export中
final Registry registry = getRegistry(originInvoker);
这句话是zookeeper得连接
return registryFactory.getRegistry(registryUrl);直接看这句话
这个resistryFactory是一个RegistryFactory$Adaptive
package com.alibaba.dubbo.registry;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
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;
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);
return extension.getRegistry(arg0);
}
}
这里extName=zookeeper
这个extension=ZookeeperRegistryFactory
ZookeeperRegistryFactory得getRegistry
public Registry getRegistry(URL url) {
url = url.setPath(RegistryService.class.getName())
.addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
.removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
String key = url.toServiceString();
// 锁定注册中心获取过程,保证注册中心单一实例
LOCK.lock();
try {
Registry registry = REGISTRIES.get(key);
if (registry != null) {
return registry;
}
registry = createRegistry(url);
if (registry == null) {
throw new IllegalStateException("Can not create registry " + url);
}
REGISTRIES.put(key, registry);
return registry;
} finally {
// 释放锁
LOCK.unlock();
}
}
首先会从REGISTRIES获取到zookeeper的节点信息,如果没有就会创建一个zookeeper的注册节点
registry = createRegistry(url);
这里进入ZookeeperRegistry的顶层构造函数
AbstractRegistry(URL url) {
忽略一段代码
this.file = file;
loadProperties();
notify(url.getBackupUrls());
}
loadProperties(); 把file中的配置文件加载到properties中
notify是遍历订阅的一些内容
然后是第二层构造函数
FailbackRegistry
public FailbackRegistry(URL url) {
super(url);
int retryPeriod = url.getParameter(Constants.REGISTRY_RETRY_PERIOD_KEY, Constants.DEFAULT_REGISTRY_RETRY_PERIOD);
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);
}
这里会定时去检测,重连注册中心,这里用到ScheduledThreadPool
然后再到ZookeeperRegistry
zkClient = zookeeperTransporter.connect(url);
这里的zookeeperTransporter是ZookeeperTransporters$Adaptve
extName=ZkClient
所以进入ZkclientZookeeperTransporter#connect
public ZookeeperClient connect(URL url) {
return new ZkclientZookeeperClient(url);
}
这里会创建一个ZkClientZookpeerClient实例
public ZkclientZookeeperClient(URL url) {
super(url);
client = new ZkClient(url.getBackupAddress());
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);
}
});
}构造函数中会创建一个ZkClient,并且给这个zkClient做一些监听
回到ZookeeperRegistry构造函数
zkClient.addStateListener(new StateListener() {
public void stateChanged(int state) {
if (state == RECONNECTED) {
try {
recover();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
});
}
之前返回的zkClient会加上状态监听
这时的registry的信息
回到ZookeeperRegistryFactory#getRegistry
接下去会吧这个rigistry放在REGISTRIES本地缓存中
回到RegistryProtocol#export方法
registry.register(registedProviderUrl);
这里会将提供者注册到zookeeper中,熟悉zookeeper的都知道,这其实是在zookeeper中创建一个节点
FailbackRegistry#register
关注doRegister(url);
点进去发现是通过之前创建的zkClient来创建一个节点
zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
回到RegistryProtocol#export方法
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
这里面会做一些订阅动作,点进去
关注
doUnsubscribe(url, listener);
ZookeeperRegistry#doSubscribe
ChildListener zkListener = listeners.get(listener);
if (zkListener == null) {
listeners.putIfAbsent(listener, new ChildListener() {
public void childChanged(String parentPath, List<String> currentChilds) {
ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds));
}
});
zkListener = listeners.get(listener);
}
zkClient.create(path, false);
List<String> children = zkClient.addChildListener(path, zkListener);
这里会给给子节点添加监听,并且通过zkClient添加到zookeeper中
注意到childChanged中的方法是 ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds));
所以我们看下ZookeeperRegistry#notify
ZookeeperRegistry的notify方法在AbstractRegistry中
其他没什么,注意有这样一句话:
saveProperties(url);
这句话就是把发生变化的节点保存在本地properties中
回到RegistryProtocol#export中
return new Exporter<T>最终会返回一个exporoter
回到ServiceConfig#doExportUrlsFor1Protocol
exporters.add(exporter);将刚刚返回的exporter加入到
exporters中
-------------------------------
花了两篇写dubbo的服务暴露,用一张图来说明服务暴露的总体架构