dubbo源码需要先了解dubbo的SPI机制!
SPI官网说明如下
spring有个配置接口叫NamespaceHandlerResolver用于实现spring自己的SPI功能,有一个实现类DefaultNamespaceHandlerResolver,会在Spring上下文初始化时扫描并加载META-INF/spring.handlers文件,dubbo的jar包的该路径中会有这个文件

文件中的内容
http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
DubboNamespaceHandler类在被Spring的SPI初始化时,DubboNamespaceHandler中的init方法会被调用。
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
public DubboNamespaceHandler() {
}
public void init() {
this.registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
this.registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
this.registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
this.registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
this.registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
this.registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
this.registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
this.registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
this.registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
this.registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
this.registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
this.registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
this.registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
}
ServiceBean是dubbo服务类启动入口,该类实现了两个重要的监听:InitializingBean和ApplicationListener。
当Spring配置文件解析完毕时,会调用InitializingBean的afterPropertiesSet(Bean被初始化时调用)。前面是一些配置解析,在最后一行代码中调用export()方法。

onApplicationEvent方法最后也是调用export()方法。

进入export()

进入super.export();到父类中:org.apache.dubbo.config.ServiceConfig,shouldDelay()是配置是否延迟启动,使用的是定时调度类

DELAY_EXPORT_EXECUTOR 类

进入 doExport(),exported防止重复发布

进入doExportUrls();

上面代码中registryURLs中的地址如下,dubbo是根据url地址中参数去通过SPI机制选择加载不同的协议发布服务。
registryURLs是个List,应为我只配置了一个注册中心,所以只返回一个。
registry://192.168.50.135:2181/org.apache.dubbo.registry.RegistryService?application=springboot-dubbo&dubbo=2.0.2&pid=21480&qos.enable=false®istry=zookeeper&release=2.7.3×tamp=1583743028098
接着进入 doExportUrlsFor1Protocol(protocolConfig, registryURLs);
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
/******************** 以下是组装一些参数 *******************/
String name = protocolConfig.getName();
if (StringUtils.isEmpty(name)) {
name = DUBBO;
}
Map<String, String> map = new HashMap<String, String>();
map.put(SIDE_KEY, PROVIDER_SIDE);
appendRuntimeParameters(map);
appendParameters(map, metrics);
appendParameters(map, application);
appendParameters(map, module);
// remove 'default.' prefix for configs from ProviderConfig
// appendParameters(map, provider, Constants.DEFAULT_KEY);
appendParameters(map, provider);
appendParameters(map, protocolConfig);
appendParameters(map, this);
if (CollectionUtils.isNotEmpty(methods)) {
for (MethodConfig method : methods) {
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");
}
}
List<ArgumentConfig> arguments = method.getArguments();
if (CollectionUtils.isNotEmpty(arguments)) {
for (ArgumentConfig argument : arguments) {
// convert argument type
if (argument.getType() != null && argument.getType().length() > 0) {
Method[] methods = interfaceClass.getMethods();
// visit all methods
if (methods != null && methods.length > 0) {
for (int i = 0; i < methods.length; i++) {
String methodName = methods[i].getName();
// target the method, and get its signature
if (methodName.equals(method.getName())) {
Class<?>[] argtypes = methods[i].getParameterTypes();
// one callback in the method
if (argument.getIndex() != -1) {
if (argtypes[argument.getIndex()].getName().equals(argument.getType())) {
appendParameters(map, argument, method.getName() + "." + argument.getIndex());
} else {
throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
}
} else {
// multiple callbacks in the method
for (int j = 0; j < argtypes.length; j++) {
Class<?> argclazz = argtypes[j];
if (argclazz.getName().equals(argument.getType())) {
appendParameters(map, argument, method.getName() + "." + j);
if (argument.getIndex() != -1 && argument.getIndex() != j) {
throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
}
}
}
}
}
}
}
} else if (argument.getIndex() != -1) {
appendParameters(map, argument, method.getName() + "." + argument.getIndex());
} else {
throw new IllegalArgumentException("Argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
}
}
}
} // end of methods for
}
if (ProtocolUtils.isGeneric(generic)) {
map.put(GENERIC_KEY, generic);
map.put(METHODS_KEY, ANY_VALUE);
} else {
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put(REVISION_KEY, revision);
}
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
if (methods.length == 0) {
logger.warn("No method found in service interface " + interfaceClass.getName());
map.put(METHODS_KEY, ANY_VALUE);
} else {
map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
}
}
if (!ConfigUtils.isEmpty(token)) {
if (ConfigUtils.isDefault(token)) {
map.put(TOKEN_KEY, UUID.randomUUID().toString());
} else {
map.put(TOKEN_KEY, token);
}
}
// export service
String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = this.findConfigedPorts(protocolConfig, name, map);
URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.hasExtension(url.getProtocol())) {
url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.getExtension(url.getProtocol()).getConfigurator(url).configure(url);
}
// 获取url中的scope参数
String scope = url.getParameter(SCOPE_KEY);
// don't export when none is configured
if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
// export to local if the config is not remote (export to remote only when config is remote)
// scope不等于远程发布一个本地服务,跳过这里
if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
exportLocal(url);
}
// export to remote if the config is not local (export to local only when config is local)
// 进入这个
if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
if (!isOnlyInJvm() && logger.isInfoEnabled()) {
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
}
// 循环所有注册中心
if (CollectionUtils.isNotEmpty(registryURLs)) {
for (URL registryURL : registryURLs) {
//if protocol is only injvm ,not register
if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
continue;
}
url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
URL monitorUrl = loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded(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(PROXY_KEY);
if (StringUtils.isNotEmpty(proxy)) {
registryURL = registryURL.addParameter(PROXY_KEY, proxy);
}
// 把实现类ref,还有接口构建成一个代理对象
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
} else {
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
/**
* @since 2.7.0
* ServiceData Store
*/
MetadataReportService metadataReportService = null;
if ((metadataReportService = getMetadataReportService()) != null) {
metadataReportService.publishProvider(url);
}
}
}
this.urls.add(url);
}
其中主要是这段代码发布服务。
// 把实现类ref,还有接口构建成一个代理对象
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
ServiceConfig 中 PROXY_FACTORY 初始化值
PROXY_FACTORY 是一个通过 SPI 加载的自适应扩展点
动态生成的代码在 ExtensionLoader.createAdaptiveExtensionClass()中可以看到!

debug查看生成的代码如下
import org.apache.dubbo.common.extension.ExtensionLoader;
public class ProxyFactory$Adaptive implements org.apache.dubbo.rpc.ProxyFactory {
public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getProxy(arg0);
}
public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0, boolean arg1) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getProxy(arg0, arg1);
}
public org.apache.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, org.apache.dubbo.common.URL arg2) throws org.apache.dubbo.rpc.RpcException {
if (arg2 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg2;
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getInvoker(arg0, arg1, arg2);
}
}
当 PROXY_FACTORY.getInvoker()就是调用上面动态生成 ProxyFactory$Adaptive.getInvoker()
此时registerURL为registry://192.168.50.135:2181/org.apache.dubbo.registry.RegistryService?application=springboot-dubbo&dubbo=2.0.2&pid=34716&qos.enable=false®istry=zookeeper&release=2.7.3×tamp=1583813331465
String extName = url.getParameter("proxy", "javassist"); //从URL中拿到 proxy 参数对应的值,如果没有就返回 javassist ,
因为没有配置 proxy 所以 extName="javassist"
返回的就是JavassistProxyFactory

在Wrapper.getWrapper中会把服务动态的生成一个代理类,有远程调用时通过代理类去调用wrapper.invokeMethod

看看生成的代理类部分代码,代码中并不是用的反射,而是通过判断方法名和参数直接调用,因为反射效率有没直接调用高,如果方法名和参数个数相同,会加上参数类型进行判断。
public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
com.david.dubbo.GoodByeService w;
try {
w = ((com.david.dubbo.GoodByeService) $1);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
try {
// 这是我接口中的三个方法
if ("sayHello".equals($2) && $3.length == 1) {
return ($w) w.sayHello((java.lang.String) $4[0]);
}
if ("sayBye".equals($2) && $3.length == 1) {
return ($w) w.sayBye((java.lang.String) $4[0]);
}
if ("sayHi".equals($2) && $3.length == 1) {
return ($w) w.sayHi((java.lang.String) $4[0]);
}
} catch (Throwable e) {
throw new java.lang.reflect.InvocationTargetException(e);
}
throw new org.apache.dubbo.common.bytecode.NoSuchMethodException("Not found method \"" + $2 + "\" in class com.david.dubbo.GoodByeService.");
}
我的接口类

回到ServiceConfig中
// 把实现类ref,还有接口构建成一个代理对象
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
返回的代理对象invoker被包装了一层,DelegateProviderMetaDataInvoker(invoker)
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
DelegateProviderMetaDataInvoker 类

继续回到ServiceConfig中
// 把实现类ref,还有接口构建成一个代理对象
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
接着看看protocol,ServiceConfig 中 protocol也是一个自适应扩展点

看看protool生成的代码Protocol$Adaptive
public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
}
public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}
public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
if (arg1 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg1;
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
}
此时registerURL为 registry://192.168.50.135:2181/org.apache.dubbo.registry.RegistryService?application=springboot-dubbo&dubbo=2.0.2&pid=34716&qos.enable=false®istry=zookeeper&release=2.7.3×tamp=1583813331465
registryURL中的protocol是register所以会走到RegisterProtocol的export方法

进入RegistryProtocol 的export()方法

发布一个本地服务
//export invoker
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
接着进入doLocalExport()方法

可以看到又被包装了一层,此时的 invoker 对象 InvokerDelegate(DelegateProviderMetaDataInvoker(invoker))
InvokerDelegate是RegistryProtocol的静态内部类。

这时候可以看到 protocol.export(invokerDelegate) 调用了export,看看 protocol是个什么类型。

并没有初始化值,只预留了一个set方法,断点打在setProtocol上

可以看到RegistryProtocol初始化是被injectExtension注入了

debug看看此时url中的协议

用的是dubbo,但是并不是一个单存的DubboProcol,而是被
ProtocolFilterWrapper(QosProtocolWrapper(ProtocolListenerWrapper(DubboProtocol)))

包装过的,最后还是会进入到DubboProtocol的export方法
进入DubboProtocol 的 export() 方法

代码中有一个很明显的通过一个url打开一个服务 openServer

这里有个 serverMap.put(key, createServer(url));

进入 Exchangers.bind(url, this.requestHandler);

调用 getExchanger(url).bind(url,handler)
这是一个静态扩展点,根据 SPI 最终会调到HeaderExchanger的bind方法

进入 HeaderExchanger

又调用了 Transporters.bind


这是一个SPI的自适应扩展点动态创建类,看看生成的类
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Transporter$Adaptive implements org.apache.dubbo.remoting.Transporter {
public org.apache.dubbo.remoting.Client connect(org.apache.dubbo.common.URL arg0, org.apache.dubbo.remoting.ChannelHandler arg1) throws org.apache.dubbo.remoting.RemotingException {
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("client", url.getParameter("transporter", "netty"));
if (extName == null)
throw new IllegalStateException("Failed to get extension (org.apache.dubbo.remoting.Transporter) name from url (" + url.toString() + ") use keys([client, transporter])");
org.apache.dubbo.remoting.Transporter extension = (org.apache.dubbo.remoting.Transporter) ExtensionLoader.getExtensionLoader(org.apache.dubbo.remoting.Transporter.class).getExtension(extName);
return extension.connect(arg0, arg1);
}
public org.apache.dubbo.remoting.Server bind(org.apache.dubbo.common.URL arg0, org.apache.dubbo.remoting.ChannelHandler arg1) throws org.apache.dubbo.remoting.RemotingException {
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("server", url.getParameter("transporter", "netty"));
if (extName == null)
throw new IllegalStateException("Failed to get extension (org.apache.dubbo.remoting.Transporter) name from url (" + url.toString() + ") use keys([server, transporter])");
org.apache.dubbo.remoting.Transporter extension = (org.apache.dubbo.remoting.Transporter) ExtensionLoader.getExtensionLoader(org.apache.dubbo.remoting.Transporter.class).getExtension(extName);
return extension.bind(arg0, arg1);
}
}
获取url中的server参数,如果没有就返回url 中的transporter,再没有就默认返回netty
url.getParameter("transporter", "netty") 返回值为 netty
String extName = url.getParameter("server", url.getParameter("transporter", "netty"));
所以 extName = "netty"
看看此时的url:
dubbo://192.168.50.1:20880/com.david.dubbo.SayHelloService?anyhost=true&application=springboot-dubbo&bean.name=ServiceBean:com.david.dubbo.SayHelloService&bind.ip=192.168.50.1&bind.port=20880&channel.readonly.sent=true&codec=dubbo&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&heartbeat=60000&interface=com.david.dubbo.SayHelloService&methods=sayHello,sayHi,sayBye&pid=23404&qos.enable=false®ister=true&release=2.7.3&side=provider×tamp=1587966019978
所以调用的是NettyTransporter,进入类的时候注意看是netty3还是netty
进入 NettyTransporter.bind

调用 NettyServer extends AbstractServer implements Server

调用 AbstractServer

doOpen() 是抽象方法,会调用子类也就是NettyServer 的,记得是Netty4

回到 NettyServer 调用 doOpen(),这里已经看到了Netty 的api调用了

绑定ip端口 bootstrap.bind(getBindAddress());

netty 启动后回到 DubboProtocol,key为ip+端口号存放netty服务
kry=192.168.50.1:20880

启动本地服务后在接着回到RegisterProtocol的export方法,这时候需要把服务地址注册到注册中心

进入Registry registry =getRegistry(originInvoker);

查看 registryFactory 发现是一个成员变量 private RegistryFactory registryFactory;
registryFactory 是动态生成 RegisterProtocol 时 injectExtension注入的,打断点查看下生成类。
import org.apache.dubbo.common.extension.ExtensionLoader;
public class RegistryFactory$Adaptive implements org.apache.dubbo.registry.RegistryFactory {
public org.apache.dubbo.registry.Registry getRegistry(org.apache.dubbo.common.URL arg0) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Failed to get extension (org.apache.dubbo.registry.RegistryFactory) name from url (" + url.toString() + ") use keys([protocol])");
org.apache.dubbo.registry.RegistryFactory extension = (org.apache.dubbo.registry.RegistryFactory) ExtensionLoader.getExtensionLoader(org.apache.dubbo.registry.RegistryFactory.class).getExtension(extName);
return extension.getRegistry(arg0);
}
}
这时候查看 registerURL 中 protocol 的值是 zookeeper,但是却没有 zookeeper,就进入抽象类里找找

进入 AbstractRegistryFactory 的 getRegistry()

这时候进入createRegistry(url);是个抽象方法,这时候就有了

进入 ZookeeperRegistryFactory ,发现有个参数要传进入 ZookeeperRegistry中,但是并没有赋值,所以还是通过了 injectExtension 做了依赖注入

打断点查看生成的类信息
import org.apache.dubbo.common.extension.ExtensionLoader;
public class ZookeeperTransporter$Adaptive implements org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter {
public org.apache.dubbo.remoting.zookeeper.ZookeeperClient connect(org.apache.dubbo.common.URL arg0) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("client", url.getParameter("transporter", "curator"));
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter) name from url (" + url.toString() + ") use keys([client, transporter])");
org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter extension = (org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter)ExtensionLoader.getExtensionLoader(org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter.class).getExtension(extName);
return extension.connect(arg0);
}
}
此时的url
zookeeper://192.168.50.135:2181/org.apache.dubbo.registry.RegistryService?application=springboot-dubbo&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=23404&qos.enable=false&release=2.7.3×tamp=1587966019973
根据url生成的是 zookeeperTransporter = CuratorZookeeperTransporter
进入 ZookeeperRegistry

zkClient = zookeeperTransporter.connect(url);这里就是调用了CuratorZookeeperTransporter
进入CuratorZookeeperTransporter并没有connect方法,所以找他的父类 AbstractZookeeperTransporter
public class CuratorZookeeperTransporter extends AbstractZookeeperTransporter {
public CuratorZookeeperTransporter() {
}
public ZookeeperClient createZookeeperClient(URL url) {
return new CuratorZookeeperClient(url);
}
}
进入AbstractZookeeperTransporter的connect

进入到 zookeeperClient = createZookeeperClient(toClientURL(url));
因为 CuratorZookeeperTransporter 重写了 createZookeeperClient 方法,所以进入 CuratorZookeeperTransporter 的

进入 CuratorZookeeperClient

进入 this.client = builder.build(); 到这里已经进入了 Curator 的api了

注册中心生成之后会通过 url 缓存起来,多个服务注册如果是同一个url就可以取到对应的注册中心
key=zookeeper://192.168.50.135:2181/org.apache.dubbo.registry.RegistryService


接下来返回 RegisterProtocol 的 export
判断获取注册中心是否成功

进入 register(registryUrl, registeredProviderUrl); 方法,前面 registryFactory 通过url 缓存了 zk ,所以现在通过url获取之前缓存的zk服务。

拿到 CuratorZookeeper 注册我们的服务地址,此时又没有了 CuratorZookeeper 实现类了

会过头看因为生成的是 ZookeeperRegistryFactory 调用的是createRegistry 所以返回的是ZookeeperRegistry,所以进去找找

进入 ZookeeperRegistry 发现其父类是 FailbackRegistry ,所以进入 FailbackRegistry


进入 org.apache.dubbo.registry.support.FailbackRegistry
进入 ZookeeperRegistry重写的 doRegister(url);

到这里又是进入了 Curator 的api了

ephemeral=true,这时候会把服务的 url 在 CuratorZookeeper 上创建一个临时节点用于服务的动态感知,动态感知基于zk的watch机制,基于心跳维持,当前dubbo挂掉的话注册在zk上的信息就会被删除,dubbo的client端就不会拿到挂掉机器注册在zk信息,所以不用担心会调用到不存在的服务。


到这里单个service的注册就结束了
简单总结:dubbo启动时会启动一个本地监听,然后会创建注册中心,最后把服务的ip端口和一些配置信息组装起来,在注册中心上创建一个临时节点。
/**
* 扩展点生成顺序
* Protocol$Adaptive
* ProxyFactory$Adaptive
* ZookeeperTransporter$Adaptive
* CacheFactory$Adaptive
* MonitorFactory$Adaptive
* Validation$Adaptive
* Cluster$Adaptive
* RegistryFactory$Adaptive
* Transporter$Adaptive
* Dispatcher$Adaptive
* ThreadPool$Adaptive
* ConfiguratorFactory$Adaptive
*/
本文详细解析了Dubbo服务注册与启动的过程,包括SPI机制的运用、ServiceConfig类的作用、服务代理对象的创建、本地服务的启动及注册到注册中心的步骤。

403

被折叠的 条评论
为什么被折叠?



