技术标签: dubbo
@Override
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
URL registryUrl = getRegistryUrl(originInvoker); //
URL providerUrl = getProviderUrl(originInvoker); // dubbo://192.168.40.17:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=dubbo-demo-provider-application&bean.name=ServiceBean:org.apache.dubbo.demo.DemoService&bind.ip=192.168.40.17&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&logger=log4j&methods=sayHello&pid=27656&release=2.7.0&side=provider&timeout=3000×tamp=1590735956489
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
// export invoker
// 根据动态配置重写了providerUrl之后,就会调用DubboProtocol或HttpProtocol去进行导出服务了
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
// url to registry
// 得到注册中心-ZookeeperRegistry
final Registry registry = getRegistry(originInvoker);
// 得到存入到注册中心去的providerUrl,会对服务提供者url中的参数进行简化
final URL registeredProviderUrl = getRegisteredProviderUrl(providerUrl, registryUrl);
// 将当前服务提供者Invoker,以及该服务对应的注册中心地址,以及简化后的服务url存入ProviderConsumerRegTable
ProviderInvokerWrapper<T> providerInvokerWrapper = ProviderConsumerRegTable.registerProvider(originInvoker,
registryUrl, registeredProviderUrl);
//to judge if we need to delay publish
//是否需要注册到注册中心
boolean register = providerUrl.getParameter(REGISTER_KEY, true);
if (register) {
// 注册服务,把简化后的服务提供者url注册到registryUrl中去
register(registryUrl, registeredProviderUrl);
providerInvokerWrapper.setReg(true);
}
//监听内容
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);
//Ensure that a new exporter instance is returned every time export
return new DestroyableExporter<>(exporter);
}
目的:获取一个Registry实例对象;
工作:
private Registry getRegistry(final Invoker<?> originInvoker) {
URL registryUrl = getRegistryUrl(originInvoker);
return registryFactory.getRegistry(registryUrl);
}
private URL getRegistryUrl(Invoker<?> originInvoker) {
// 将registry://xxx?xx=xx®istry=zookeeper 转为 zookeeper://xxx?xx=xx
URL registryUrl = originInvoker.getUrl();
if (REGISTRY_PROTOCOL.equals(registryUrl.getProtocol())) {
String protocol = registryUrl.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY);
registryUrl = registryUrl.setProtocol(protocol).removeParameter(REGISTRY_KEY);
}
return registryUrl;
}
是一个接口;
@SPI("dubbo")
public interface RegistryFactory {
@Adaptive({
"protocol"})
Registry getRegistry(URL url);
}
@Override
public Registry getRegistry(URL url) {
url = URLBuilder.from(url)
.setPath(RegistryService.class.getName())
.addParameter(INTERFACE_KEY, RegistryService.class.getName())
.removeParameters(EXPORT_KEY, REFER_KEY)
.build();
String key = url.toServiceStringWithoutResolving();
// Lock the registry access process to ensure a single instance of the registry
LOCK.lock();
try {
Registry registry = REGISTRIES.get(key);
if (registry != null) {
return registry;
}
//create registry by spi/ioc
registry = createRegistry(url);
if (registry == null) {
throw new IllegalStateException("Can not create registry " + url);
}
REGISTRIES.put(key, registry);
return registry;
} finally {
// Release the lock
LOCK.unlock();
}
}
protected abstract Registry createRegistry(URL url);
创建了一个ZookeeperRegistry实例;
public class ZookeeperRegistryFactory extends AbstractRegistryFactory {
private ZookeeperTransporter zookeeperTransporter;
/**
* Invisible injection of zookeeper client via IOC/SPI
* @param zookeeperTransporter
*/
public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) {
this.zookeeperTransporter = zookeeperTransporter;
}
@Override
public Registry createRegistry(URL url) {
return new ZookeeperRegistry(url, zookeeperTransporter);
}
}
创建ZookeeperRegistry实例;
public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
super(url);
if (url.isAnyHost()) {
throw new IllegalStateException("registry address == null");
}
String group = url.getParameter(GROUP_KEY, DEFAULT_ROOT);
if (!group.startsWith(PATH_SEPARATOR)) {
group = PATH_SEPARATOR + group;
}
this.root = group;
zkClient = zookeeperTransporter.connect(url);
zkClient.addStateListener(state -> {
if (state == StateListener.RECONNECTED) {
try {
recover();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
});
}
创建完ZookeeperRegistry实例后,层层返回, 返回到获取Registry的地方;
目的: 简化删除URL中的一些无用数据;
// 得到存入到注册中心去的providerUrl,会对服务提供者url中的参数进行简化
final URL registeredProviderUrl = getRegisteredProviderUrl(providerUrl, registryUrl);
工作:
/**
* Return the url that is registered to the registry and filter the url parameter once
* 得到能存入到注册中心去的providerUrl
* @param providerUrl
* @return url to registry.
*/
private URL getRegisteredProviderUrl(final URL providerUrl, final URL registryUrl) {
//The address you see at the registry
// 默认都是走这里
if (!registryUrl.getParameter(SIMPLIFIED_KEY, false)) {
// 移除key以"."开始的参数,以及其他跟服务本身没有关系的参数,比如监控,绑定ip,qosd等等
return providerUrl.removeParameters(getFilteredKeys(providerUrl)).removeParameters(
MONITOR_KEY, BIND_IP_KEY, BIND_PORT_KEY, QOS_ENABLE, QOS_HOST, QOS_PORT, ACCEPT_FOREIGN_IP, VALIDATION_KEY,
INTERFACES);
} else {
String extraKeys = registryUrl.getParameter(EXTRA_KEYS_KEY, "");
// if path is not the same as interface name then we should keep INTERFACE_KEY,
// otherwise, the registry structure of zookeeper would be '/dubbo/path/providers',
// but what we expect is '/dubbo/interface/providers'
// 如果path不等于interface的值,那么则把INTERFACE_KEY添加到extraKeys中
if (!providerUrl.getPath().equals(providerUrl.getParameter(INTERFACE_KEY))) {
if (StringUtils.isNotEmpty(extraKeys)) {
extraKeys += ",";
}
extraKeys += INTERFACE_KEY;
}
// paramsToRegistry包括了DEFAULT_REGISTER_PROVIDER_KEYS和extraKeys
String[] paramsToRegistry = getParamsToRegistry(DEFAULT_REGISTER_PROVIDER_KEYS
, COMMA_SPLIT_PATTERN.split(extraKeys));
// 生成只含有paramsToRegistry的对应的参数,并且该参数不能为空
return URL.valueOf(providerUrl, paramsToRegistry, providerUrl.getParameter(METHODS_KEY, (String[]) null));
}
}
//过滤掉以"."开头的key, 返回一个数组;
private static String[] getFilteredKeys(URL url) {
Map<String, String> params = url.getParameters();
// 过滤url的参数,找到startsWith(HIDE_KEY_PREFIX)的key
if (CollectionUtils.isNotEmptyMap(params)) {
return params.keySet().stream()
.filter(k -> k.startsWith(HIDE_KEY_PREFIX))
.toArray(String[]::new);
} else {
return new String[0];
}
}
目的: 当前服务提供者Invoker,以及该服务对应的注册中心地址,以及简化后的服务url存入ProviderConsumerRegTable
工作:
public static <T> ProviderInvokerWrapper<T> registerProvider(Invoker<T> invoker, URL registryUrl, URL providerUrl) {
ProviderInvokerWrapper<T> wrapperInvoker = new ProviderInvokerWrapper<>(invoker, registryUrl, providerUrl);
String serviceUniqueName = providerUrl.getServiceKey();
// 根据
ConcurrentMap<Invoker, ProviderInvokerWrapper> invokers = providerInvokers.get(serviceUniqueName);
if (invokers == null) {
providerInvokers.putIfAbsent(serviceUniqueName, new ConcurrentHashMap<>());
invokers = providerInvokers.get(serviceUniqueName);
}
invokers.put(invoker, wrapperInvoker);
return wrapperInvoker;
}
注册到Zookeeper注册中心;
boolean register = providerUrl.getParameter(REGISTER_KEY, true);
if (register) {
// 注册服务,把简化后的服务提供者url注册到registryUrl中去
register(registryUrl, registeredProviderUrl);
providerInvokerWrapper.setReg(true);
}
public void register(URL registryUrl, URL registeredProviderUrl) {
Registry registry = registryFactory.getRegistry(registryUrl);
// 调用ZookeeperRegistry的register方法
registry.register(registeredProviderUrl);
}
//FailbackRegistry#register
@Override
public void register(URL url) {
super.register(url);
removeFailedRegistered(url);
removeFailedUnregistered(url);
try {
// Sending a registration request to the server side
doRegister(url);
} catch (Exception e) {
Throwable t = e;
//省略部分代码;
// Record a failed registration request to a failed list, retry regularly
addFailedRegistered(url);
}
}
目的:给Zookeeper发送请求,创建一个值toUrlPath(url)为动态的配置结点;
@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);
}
}
获取结点的值;
//"/dubbo/com.demo.DemoService/providers/#{url}"
// toCategoryPath(url) ⇒ "/dubbo/com.demo.DemoService/providers"
// PATH_SEPARATOR ==> "/"
//URL.encode(url.toFullString())==>对url进行中文编码
private String toUrlPath(URL url) {
return toCategoryPath(url) + PATH_SEPARATOR + URL.encode(url.toFullString());
}
//返回的结果:"/dubbo/com.demo.DemoService/providers"
// toServicePath(url) ⇒ "/dubbo/com.demo.DemoService"
// PATH_SEPARATOR ==> "/"
// 获取URL的catogory的值, 默认为providers;
private String toCategoryPath(URL url) {
return toServicePath(url) + PATH_SEPARATOR + url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
}
//结果: "/dubbo/com.demo.DemoService"
//toRootDir() ---> "/dubbo/"
//URL.encode(name) --> 对URL的name属性进行URL编码; name的值为 com.demo.DemoService
private String toServicePath(URL url) {
String name = url.getServiceInterface();
if (ANY_VALUE.equals(name)) {
return toRootPath();
}
return toRootDir() + URL.encode(name);
}
//结果为:根节点 的值 + “/”, 这里为 "/dubbo/"
private String toRootDir() {
if (root.equals(PATH_SEPARATOR)) {
return root;
}
return root + PATH_SEPARATOR;
}
一个服务导出成功后,会生成对应的Exporter:
作者:会笑的饼干链接:https://www.zhihu.com/question/22094277/answer/99993554来源:知乎1.如果你喜欢正经的XMind 和 MindManager都可以,个人感觉MindManager好用一些(因为每个框在上下左右都可以增加集合),但是需付费MindManager:全球领先思维导图解决方案 思维导图神器
本文将从GraphQL是什么,为什么要使用GraphQL,使用GraphQL创建简单例子,以及GraphQL实战,四个方面对GraphQL进行阐述。说得不对的地方,希望大家指出斧正。github项目地址:https://github.com/Charming2015/graphql-todolist一、GraphQL是什么?关于GraphQL是什么,网上一搜一大堆。根据官网的解释就是一...
这次教程中,我们将学会如何创建镜面显示效果,它利用到剪裁平面,蒙板缓存等OpenGL中一些高级的技巧。在这课里,我们将创建真正的反射,基于物理的,相信你一定很期待!
1.论文摘要Transformer 为基础的模型擅长捕捉content-based gloabl interactions;卷积更适合捕捉局部的local features. 本文将两者的优势结合起来,并且使用的参数更少,在Lbrispeech 上达到了SOTA with 2.1/4.3% 的wer.2. 模型结构Multi-Headed Self-Attention ModuleConvolution ModuleFeed Forward Module两个线性层中间加一个非线性激活
转自:https://www.jianshu.com/p/f581cf9360a2背景介绍 什么是npm?npm(node package manager)是nodejs的包管理器,用于node插件管理(包括安装、卸载、管理依赖等), NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,它是 Node 获得成功的重要原因之一。常见的使用场景有以下几种:...
大家了解JL150-P2000-001L6C拉线位移编码器这款产品吗JL150-P2000-001L6C拉线位移编码器是一款为咱山东用户定做的一款传感器产品,量程2000mm,它的输入电压:DC24V,输出信号为集电极开路,使用的编码器为欧姆龙编码器,精量电子小编来为大家分享一下此类传感器的内容知识:JL150-P2000-001L6C拉线位移编码器性能特点:安装方便,设有备用安装基准面,根据需要多种选择;安装空间小,安装难度低;无需导向,机械公差不影响测量精度;外壳和线轮均经过防腐处理,钢丝绳为不锈
AOP(面向切面编程)面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ,我们知道,面向对象的特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中往往称为职责分配。实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。但是人们也发现,在分散代码的同时,也增加了代码的...
DHCP动态分配ip地址
Java中Map的merge、compute、computeIfAbsent、computeIfPresent的用法以及使用场景merge的用法 merge :default V merge(K key, V value,BiFunction之前的实现现在我们要做一个操作,把list中的对象,按照属性男女分组,然后把年龄汇总。如果是1.8之前的实现。 /**...
页面分页对于程序员来说最熟悉不过,在WEB开发中经常需要对页面进行分页,jQuery插件JQuery Pager分页器能轻松实现javascript分页功能,只需要几行代码,就可以轻松搞定,实例效果图如下: 简单明了,下面我介绍一下实现过程: 首先需要使用jQuery库文件和JQuery Pager库文件,请点击下载。 分页样式page
说明:这是2007年复习SCJP期间的学习笔记(JavaSE 5.0),有部分遗失。现在整理一下发到Blog上,一方面做个备份,另一方面分享出来,希望对需要的人有用。-----------------------------------------第三部分 赋值1、 八进制整数:在前面加一个0,后面是0-7。int six=06; //6int seven=07...
南京市委、市政府日前公布了《南京市建设中国“互联网+”名城实施方案》,其中提出要建立覆盖个人、企事业单位和社会组织的公共信用平台,市民卡将加载个人信用记录功能。根据制定的目标,到2020年,南京要培育发展180家互联网行业龙头骨干企业,中国互联网百强企业累计达8家、互联网知名品牌12个。在“互联网+”智慧城市应用方面,南京市提出,要加快推进“无线城市...