注册服务的过程
###加载注册中心链接
//加载注册中心,用于链接,dubbo支持多注册中心
//注册中心 <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
List<URL> registryURLs = ConfigValidationUtils.loadRegistries(this, true);
//协议,可以暴露多协议,用,分开
//dubbo 协议、端口号 <dubbo:protocol name="dubbo" port="2181"/>
ProtocolConfig
###服务导出
//解析配置
Map<String, String> map = new HashMap<String, String>();
"side" -> "provider"
"metadata-type" -> "remote"
"application" -> "family-provider"
"release" -> ""
"deprecated" -> "false"
"dubbo" -> "2.0.2"
"pid" -> "9812"
"dynamic" -> "true"
"interface" -> "org.apache.dubbo.service.EsProductService"
"generic" -> "false"
"timestamp" -> "1591705088689"
//封装成URL dubbo协议、端口、
//dubbo://192.168.56.1:20880/org.apache.dubbo.service.EsProductService?
//anyhost=true&application=family-provider&
//bind.ip=192.168.56.1&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&
//interface=org.apache.dubbo.service.EsProductService&metadata-type=remote&
//methods=searchPage&pid=11384&release=&side=provider×tamp=1591706038181
URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
//创建invoker
//ref服务实例对象、interfaceClass接口、url注册中心:将dubbo服务注册到添加中心
//dubbo://192.168.56.1:20880/org.apache.dubbo.service.EsProductService?
//anyhost=true&application=family-provider&bind.ip=192.168.56.1&
//bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&
//interface=org.apache.dubbo.service.EsProductService&metadata-type=remote&
//methods=searchPage&pid=5660&release=&side=provider×tamp=1591708521903
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass,
registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
//建立通信
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
//提供发现能力 RegistryProtocol
//通过url 加载 Registery,建立链接 final Registry registry = getRegistry(originInvoker);
//将url 注册 到(zk)远程 final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
//创建监听 监听对象:
//final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
//overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
//向注册中心订阅
//registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
public <T> Exporter<T> export(final Invoker<T> originInvoker);
//服务暴露 DubboProtocol
//将我们的Invoker对象 包装为 DubboExporter 对象
//启动服务,创建Netty服务,此时启动了一个IP+Port的Netty服务,可以提供远程服务调用的能力
public <T> Exporter<T> export(Invoker<T> invoker);
###以上代码只是提供了一个(IP+PORT+Bean+Method)服务,但是这时候消费端是不知道有这么一个服务的
RegistryProtocol
@Override
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
URL registryUrl = getRegistryUrl(originInvoker);
// url to export locally
URL providerUrl = getProviderUrl(originInvoker);
// 订阅override数据
// FIXME 提供者订阅时,会影响同一JVM即暴露服务,又引用同一服务的的场景,
// 因为subscribed以服务名为缓存的key,导致订阅信息覆盖。
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
// 在本地暴露服务
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
//registry provider
// 拿到zookeeper的注册信息
final Registry registry = getRegistry(originInvoker);
// 获取需要暴露provider的url对象,dubbo的注册订阅通信都是以url作为参数传递的
final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
// decide if we need to delay publish
boolean register = providerUrl.getParameter(REGISTER_KEY, true);
if (register) {
//注册服务到注册中心zooker
register(registryUrl, registeredProviderUrl);
}
// register stated url on provider model
registerStatedUrl(registryUrl, registeredProviderUrl, register);
// 暴露的同时订阅服务,另外会在zk上创建configurators节点信息
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);
notifyExport(exporter);
//保证每次export都返回一个新的exporter实例
return new DestroyableExporter<>(exporter);
}
DubboProtocol
@Override
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);
// 这里会判断是否是stub服务,默认false
Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT);
// 判断是否是callback服务
Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false);
if (isStubSupportEvent && !isCallbackservice) {
String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY);
if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
if (logger.isWarnEnabled()) {
logger.warn(new IllegalStateException("consumer [" + url.getParameter(INTERFACE_KEY) +
"], has set stubproxy support event ,but no stub methods founded."));
}
}
}
// 开启Netty服务
openServer(url);
optimizeSerialization(url);
return exporter;
}
服务暴露
将xxxService这个实例对象转换成AbstractProxyInvoker
将Invoker对象 包装为 DobboExporter
创建Transporter
创建Server(NettyServer)
服务注册
连接Zookeeper
创建Provier下的临时节点(绑定服务器节点的URL)
监听Zookeeper的configurators节点
RPC原理
为什么要用Dubbo
1.各个应用节点中的url管理维护困难、依赖关系很模糊 -注册中心
2.每个应用节点的性能、并发量、响应时间、没办法评估 -监控中心
protocol 协议
webservice、Thrift、hessain、http、dubbo、rmi
发布服务
dubbo【协议】://ip:20880【端口】/com.xxx.provider.service.xxxService【接口名称】?参数【服务端配置】
URL
dubbo://192.168.56.1:20880/com.city.service.DemoService?
anyhost=true&
application=hello-world-app&
bind.ip=192.168.56.1&
bind.port=20880&
dubbo=2.6.0&
generic=false&
interface=com.city.service.DemoService&methods=sayHello&
pid=11508&
side=provider&
timestamp=1591614320441
配置参数
发布服务参数介绍
dubbo.application.name = 提供方应用信息,用于计算依赖关系
dubbo.registry.address = 注册中心,N/A表示不使用注册中心
dubbo.protocol.name = 使用的协议
dubbo.protocol.port = 端口号
dubbo.service.interface = 提供服务的接口名称
dubbo.service.ref = 服务的引用实现
zk节点
zk 存放节点路径
/dubbo/com.city.common.service.EsProductService/configurators
/dubbo/com.city.common.service.EsProductService/providers
providers 下面挂着url
临时节点:url
持久化节点:/dubbo/com.city.common.service.EsProductService/providers
/dubbo/com.city.common.service.EsProductService/configurators
调用服务
基于spring 配置文件拓展
NamespaceHander 注册BeanDefinitonParser,利用它来解析
BeanDefintionParser 解析配置文件元素
spring 默认加载jar 包下/META-INF/spring.handlers 找到对象的NamespaceHander
ServiceConfig<T> implements
InitializingBean, 当spring容器初始化完后,会调用afterPropertiesSet方法
DisposableBean, 当容器被销毁的时候会调用destroy方法
ApplicationContextAware, spring容器初始化以后主动注入ApplicationContext对象
BeanNameAware, 获取bean本身id属性
ApplicationEventPublisherAware 事件通知