1.registryURLs处理
接着上节本地服务暴露过程,我们继续看下面的代码
if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {
// export to local if the config is not remote (export to remote only when config is remote)
if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
exportLocal(url); //本地暴露
}
// export to remote if the config is not local (export to local only when config is 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.isEmpty()) {
//遍历registryURLs进行远程服务暴露
for (URL registryURL : registryURLs) {
url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
URL monitorUrl = loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
}
// For providers, this is used to enable custom proxy to generate invoker
String proxy = url.getParameter(Constants.PROXY_KEY);
if (StringUtils.isNotEmpty(proxy)) {
registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
}
//使用proxyFactory生成一个invoker 其实就是一个代理对象
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
//创建DelegateProvoderMetaInvoker对象进行包装
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
} else { //没有registryURLs
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
}
}
其中exportLocal就是本地暴露相关处理,下面的这部分内容就是远程暴露相关的处理,这里首先会遍历所有的注册中心,然后挨个儿进行处理,最终的url信息如下图:
2.生成代理Invoker
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
这行代码会生成对应的代理对象,具体的生成方式上节详细说过,这里不再多说,断点一下这个Invoker,如下图:
3.对Invoker进行包装
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
这行代码创建DelegateProvoderMetaInvoker对象对Invoker进行包装,主要是把原始的配置信息跟invoker绑在一块。DelegateProvoderMetaInvoker.java
public class DelegateProviderMetaDataInvoker<T> implements Invoker {
protected final Invoker<T> invoker;
private ServiceConfig metadata;
public DelegateProviderMetaDataInvoker(Invoker<T> invoker,ServiceConfig metadata) {
this.invoker = invoker;
this.metadata = metadata;
}
//省略代码
}
4.export服务暴露
与本地暴露一样,这里也会先走到ProtocolFilterWrapper的export方法,其源码如下:
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
//invoker的url地址中的Protocol是否为registry
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}
这里的registry非空的,所以会走到if条件里的内容,接下来会走到QosProtocolWrapper中的export方法,其源码如下:
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
startQosServer(invoker.getUrl());
return protocol.export(invoker);
}
return protocol.export(invoker);
}
这里有一个startQosServer操作,这里我们跟进去看一下
private void startQosServer(URL url) {
try {
//获取QOS_ENABLE(qos.enable)的值,未设置默认为true
boolean qosEnable = url.getParameter(QOS_ENABLE,true);
if (!qosEnable) { //若为false 直接返回
logger.info("qos won't be started because it is disabled. " +
"Please check dubbo.application.qos.enable is configured either in system property, " +
"dubbo.properties or XML/spring boot configuration.");
return;
}
//将hasStarted的值从false修改为true 若修改失败直接返回
if (!hasStarted.compareAndSet(false, true)) {
return;
}
//获取端口 若未获取到,则返回DEFAULT_PORT(22222)
int port = url.getParameter(QOS_PORT, DEFAULT_PORT);
//获取url中qos.accept.foreign.ip的值,为空默认为false
boolean acceptForeignIp = Boolean.parseBoolean(url.getParameter(ACCEPT_FOREIGN_IP,"false"));
//获取一个Server实例
Server server = com.alibaba.dubbo.qos.server.Server.getInstance();
//设置server端口
server.setPort(port);
server.setAcceptForeignIp(acceptForeignIp);
//启动server
server.start();
} catch (Throwable throwable) {
logger.warn("Fail to start qos server: ", throwable);
}
}
这里获取了一个server的实例然后绑定了一个端口,这里是从url中获取qos.port的值,如果未获取到,则设置为22222,然后调用了server的start方法,我们看一下获取server的过程:
private static final Server INSTANCE = new Server();
public static final Server getInstance() {
return INSTANCE;
}
private Server() {
this.welcome = DubboLogo.dubbo;
}
就是返回一个单例的Server对象,设置了welcome属性,如下: