1.ServiceConfig#export
服务提供方在启动部署时,dubbo会调用ServiceConfig#export
来激活服务发布流程,如下所示:
查看export
源码可知,总共有三种服务导出选项:
java public synchronized void export() { //1. 是否导出 if (!shouldExport()) { return; } ... //2.延迟导出 if (shouldDelay()) { DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS); } else { //3.立刻导出 doExport(); } }
2.ServiceConfig#doExport
此方法主要是根据设置的属性进行合法性检查,主要包含是否已被导出,doExportUrls();
3.doExportUrls
4.ConfigValidationUtils#loadRegistries
此方法用来加载所有的服务注册中心对象,在dubbo中,一个service可以被注册到多个注册中心。 通过
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
5.doExportUrlsFor1Protocol
在此方法中会将所有的参数封装成
org.apache.dubbo.common.URL
对象,然后执行具体的服务导出。
具体过程分为:
scope
):
org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol
)
dubbo-2.7.0
开始,新增加了WritableMetadataService
来存储dubbo 服务的元数据,元数据可以存储在远端配置中心和本地,默认是存储在本地,通过设置:METADATA_KEY = "metadata"
java /** * @since 2.7.0 * ServiceData Store */ WritableMetadataService metadataService = WritableMetadataService.getExtension(url.getParameter(METADATA_KEY, DEFAULT_METADATA_STORAGE_TYPE)); if (metadataService != null) { metadataService.publishServiceDefinition(url); }
由于protocol
和PROXY_FACTORY
都是扩展适配类,跟踪代码我们可以发现:
PROXY_FACTORY.getInvoker
的时候实际上首先执行扩展接口ProxyFactory
的适配类ProxyFactory$Adaptive
的getInvoker
方法,根据URL
中参数proxy
的设置类型选择具体的代理工厂,默认使用的是javassist
,,因此又调用了org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory#getInvoker
来获取代理实现类,代码如下:上面代码有2个目的:
inal Wrapper wrapper = Wrapper.getWrapper(...);
用来生成具体serviceImpl
的包装类,减少反射的性能损耗;return new AbstractProxyInvoker<T>...
返回了一个抽象的代理invoker
,并且重写了doInvoker
方法,重写之后使用包装类中的invokeMethod
来调用方法。 经过上述2步,服务提供方就将具体的实现类转换为Invoker
代理。
protocol.export()
,实际上也是调用了Protocol$Adaptive#export()
方法,同时也分为两种情况 RegistryProtocol#export
InjvmProtocol#export
由于dubbo的增强SPI
特性支持,injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
,则在调用之前会一层一层调用,ProtocolFilterWrapper
->ProtocolListenerWrapper
->QosProtocolWrapper
,最后会调用export
方法,此方法会将Invoker
转换为Exporter
对象,在org.apache.dubbo.registry.integration.RegistryProtocol#export
方法中,org.apache.dubbo.registry.integration.RegistryProtocol#doLocalExport
方法启NettyServer
来监听服务,org.apache.dubbo.registry.integration.RegistryProtocol#register
将当前的服务注册到注册中心。
doLocalExport
是如何启动NettyServer
呢?
可以看到代码执行到openServer
,因为key=getAddress()=ip+port
,因此,同一台机器只会开启一个NettyServer
.
对于org.apache.dubbo.remoting.Transporter 的适配类选择有三种:MinaTransporter、 NettyTransporter、GrizzlyTransporter,关于JavaNIO:Apache Mina、JBoss Netty、Sun Grizzly 框架对比:传送门
org.apache.dubbo.registry.integration.RegistryProtocol#export
方法,继续执行将服务注册到注册中心,我们以Zookeeper
为例:
RegistryFactory
是一个SPI扩展接口,代码中设置的为zookeeper
,因此这里调用的是ZookeeperRegistryFactory
,继承自:org.apache.dubbo.registry.support.AbstractRegistryFactory#getRegistry(org.apache.dubbo.common.URL)
,在此方法中调用了createRegistry
,但是ZookeeperRegistryFactory
重写了createRegistry
,因此具体调用的是ZookeeperRegistryFactory#createRegistry
,该方法返回了一个new ZookeeperRegistry(url, zookeeperTransporter)
实例对象。RegistryProtocol#register
方法执行注册动作,首先获取到我们在上一步找到的注册中心ZookeeperRegistry
,ZookeeperRegistry
执行父类org.apache.dubbo.registry.support.FailbackRegistry#register
,在该方法中会调用抽象方法:doRegister
,ZookeeperRegistry
重写了改方法,则执行ZookeeperRegistry#doRegister
,如下:
@Override public void doRegister(URL url) { try { zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true)); } catch (Throwable e) { throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e); } }toUrlPath
方法会把org.apache.dubbo.common.URL
转换格式后存储到zookeeper,如下:
至此,服务消费端就可以从注册中心获取服务提供service进行调用了,下节我们继续来分析,消费端是如何从注册中心拉取service进行处理的。