com.alibaba.dubbo.registry.integration.RegistryProtocol Maven / Gradle / Ivy
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.registry.integration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.common.utils.UrlUtils;
import com.alibaba.dubbo.registry.NotifyListener;
import com.alibaba.dubbo.registry.Registry;
import com.alibaba.dubbo.registry.RegistryFactory;
import com.alibaba.dubbo.registry.RegistryService;
import com.alibaba.dubbo.rpc.Exporter;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Protocol;
import com.alibaba.dubbo.rpc.ProxyFactory;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Cluster;
import com.alibaba.dubbo.rpc.cluster.Configurator;
import com.alibaba.dubbo.rpc.protocol.InvokerWrapper;
/**
* RegistryProtocol
*
* @author william.liangf
* @author chao.liuc
*/
public class RegistryProtocol implements Protocol {
private Cluster cluster;
public void setCluster(Cluster cluster) {
this.cluster = cluster;
}
private Protocol protocol;
public void setProtocol(Protocol protocol) {
this.protocol = protocol;
}
private RegistryFactory registryFactory;
public void setRegistryFactory(RegistryFactory registryFactory) {
this.registryFactory = registryFactory;
}
private ProxyFactory proxyFactory;
public void setProxyFactory(ProxyFactory proxyFactory) {
this.proxyFactory = proxyFactory;
}
public int getDefaultPort() {
return 9090;
}
private static RegistryProtocol INSTANCE;
public RegistryProtocol() {
INSTANCE = this;
}
public static RegistryProtocol getRegistryProtocol() {
if (INSTANCE == null) {
ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(Constants.REGISTRY_PROTOCOL); // load
}
return INSTANCE;
}
private final Map overrideListeners = new ConcurrentHashMap();
public Map getOverrideListeners() {
return overrideListeners;
}
//用于解决rmi重复暴露端口冲突的问题,已经暴露过的服务不再重新暴露
//providerurl <--> exporter
private final Map> bounds = new ConcurrentHashMap>();
private final static Logger logger = LoggerFactory.getLogger(RegistryProtocol.class);
public Exporter export(final Invoker originInvoker) throws RpcException {
//export invoker
final ExporterChangeableWrapper exporter = doLocalExport(originInvoker);
//registry provider
final Registry registry = getRegistry(originInvoker);
final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
registry.register(registedProviderUrl);
// 订阅override数据
// FIXME 提供者订阅时,会影响同一JVM即暴露服务,又引用同一服务的的场景,因为subscribed以服务名为缓存的key,导致订阅信息覆盖。
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
//保证每次export都返回一个新的exporter实例
return new Exporter() {
public Invoker getInvoker() {
return exporter.getInvoker();
}
public void unexport() {
try {
exporter.unexport();
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
try {
registry.unregister(registedProviderUrl);
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
try {
overrideListeners.remove(overrideSubscribeUrl);
registry.unsubscribe(overrideSubscribeUrl, overrideSubscribeListener);
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
}
};
}
@SuppressWarnings("unchecked")
private ExporterChangeableWrapper doLocalExport(final Invoker originInvoker){
String key = getCacheKey(originInvoker);
ExporterChangeableWrapper exporter = (ExporterChangeableWrapper) bounds.get(key);
if (exporter == null) {
synchronized (bounds) {
exporter = (ExporterChangeableWrapper) bounds.get(key);
if (exporter == null) {
final Invoker> invokerDelegete = new InvokerDelegete(originInvoker, getProviderUrl(originInvoker));
exporter = new ExporterChangeableWrapper((Exporter)protocol.export(invokerDelegete), originInvoker);
bounds.put(key, exporter);
}
}
}
return (ExporterChangeableWrapper) exporter;
}
/**
* 对修改了url的invoker重新export
* @param originInvoker
* @param newInvokerUrl
*/
@SuppressWarnings("unchecked")
private void doChangeLocalExport(final Invoker originInvoker, URL newInvokerUrl){
String key = getCacheKey(originInvoker);
final ExporterChangeableWrapper exporter = (ExporterChangeableWrapper) bounds.get(key);
if (exporter == null){
logger.warn(new IllegalStateException("error state, exporter should not be null"));
return ;//不存在是异常场景 直接返回
} else {
final Invoker invokerDelegete = new InvokerDelegete(originInvoker, newInvokerUrl);
exporter.setExporter(protocol.export(invokerDelegete));
}
}
/**
* 根据invoker的地址获取registry实例
* @param originInvoker
* @return
*/
private Registry getRegistry(final Invoker> originInvoker){
URL registryUrl = originInvoker.getUrl();
if (Constants.REGISTRY_PROTOCOL.equals(registryUrl.getProtocol())) {
String protocol = registryUrl.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_DIRECTORY);
registryUrl = registryUrl.setProtocol(protocol).removeParameter(Constants.REGISTRY_KEY);
}
return registryFactory.getRegistry(registryUrl);
}
/**
* 返回注册到注册中心的URL,对URL参数进行一次过滤
* @param originInvoker
* @return
*/
private URL getRegistedProviderUrl(final Invoker> originInvoker){
URL providerUrl = getProviderUrl(originInvoker);
//注册中心看到的地址
final URL registedProviderUrl = providerUrl.removeParameters(getFilteredKeys(providerUrl)).removeParameter(Constants.MONITOR_KEY);
return registedProviderUrl;
}
private URL getSubscribedOverrideUrl(URL registedProviderUrl){
return registedProviderUrl.setProtocol(Constants.PROVIDER_PROTOCOL)
.addParameters(Constants.CATEGORY_KEY, Constants.CONFIGURATORS_CATEGORY,
Constants.CHECK_KEY, String.valueOf(false));
}
/**
* 通过invoker的url 获取 providerUrl的地址
* @param origininvoker
* @return
*/
private URL getProviderUrl(final Invoker> origininvoker){
String export = origininvoker.getUrl().getParameterAndDecoded(Constants.EXPORT_KEY);
if (export == null || export.length() == 0) {
throw new IllegalArgumentException("The registry export url is null! registry: " + origininvoker.getUrl());
}
URL providerUrl = URL.valueOf(export);
return providerUrl;
}
/**
* 获取invoker在bounds中缓存的key
* @param originInvoker
* @return
*/
private String getCacheKey(final Invoker> originInvoker){
URL providerUrl = getProviderUrl(originInvoker);
String key = providerUrl.removeParameters("dynamic", "enabled").toFullString();
return key;
}
@SuppressWarnings("unchecked")
public Invoker refer(Class type, URL url) throws RpcException {
url = url.setProtocol(url.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_REGISTRY)).removeParameter(Constants.REGISTRY_KEY);
Registry registry = registryFactory.getRegistry(url);
if (RegistryService.class.equals(type)) {
return proxyFactory.getInvoker((T) registry, type, url);
}
// group="a,b" or group="*"
Map qs = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY));
String group = qs.get(Constants.GROUP_KEY);
if (group != null && group.length() > 0 ) {
if ( ( Constants.COMMA_SPLIT_PATTERN.split( group ) ).length > 1
|| "*".equals( group ) ) {
return doRefer( getMergeableCluster(), registry, type, url );
}
}
return doRefer(cluster, registry, type, url);
}
private Cluster getMergeableCluster() {
return ExtensionLoader.getExtensionLoader(Cluster.class).getExtension("mergeable");
}
private Invoker doRefer(Cluster cluster, Registry registry, Class type, URL url) {
RegistryDirectory directory = new RegistryDirectory(type, url);
directory.setRegistry(registry);
directory.setProtocol(protocol);
URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, NetUtils.getLocalHost(), 0, type.getName(), directory.getUrl().getParameters());
if (! Constants.ANY_VALUE.equals(url.getServiceInterface())
&& url.getParameter(Constants.REGISTER_KEY, true)) {
registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
Constants.CHECK_KEY, String.valueOf(false)));
}
directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY,
Constants.PROVIDERS_CATEGORY
+ "," + Constants.CONFIGURATORS_CATEGORY
+ "," + Constants.ROUTERS_CATEGORY));
return cluster.join(directory);
}
//过滤URL中不需要输出的参数(以点号开头的)
private static String[] getFilteredKeys(URL url) {
Map params = url.getParameters();
if (params != null && !params.isEmpty()) {
List filteredKeys = new ArrayList();
for (Map.Entry entry : params.entrySet()) {
if (entry != null && entry.getKey() != null && entry.getKey().startsWith(Constants.HIDE_KEY_PREFIX)) {
filteredKeys.add(entry.getKey());
}
}
return filteredKeys.toArray(new String[filteredKeys.size()]);
} else {
return new String[] {};
}
}
public void destroy() {
List> exporters = new ArrayList>(bounds.values());
for(Exporter> exporter :exporters){
exporter.unexport();
}
bounds.clear();
}
/*重新export 1.protocol中的exporter destory问题
*1.要求registryprotocol返回的exporter可以正常destroy
*2.notify后不需要重新向注册中心注册
*3.export 方法传入的invoker最好能一直作为exporter的invoker.
*/
private class OverrideListener implements NotifyListener {
private volatile List configurators;
private final URL subscribeUrl;
public OverrideListener(URL subscribeUrl) {
this.subscribeUrl = subscribeUrl;
}
/*
* provider 端可识别的override url只有这两种.
* override://0.0.0.0/serviceName?timeout=10
* override://0.0.0.0/?timeout=10
*/
public void notify(List urls) {
List result = null;
for (URL url : urls) {
URL overrideUrl = url;
if (url.getParameter(Constants.CATEGORY_KEY) == null
&& Constants.OVERRIDE_PROTOCOL.equals(url.getProtocol())) {
// 兼容旧版本
overrideUrl = url.addParameter(Constants.CATEGORY_KEY, Constants.CONFIGURATORS_CATEGORY);
}
if (! UrlUtils.isMatch(subscribeUrl, overrideUrl)) {
if (result == null) {
result = new ArrayList(urls);
}
result.remove(url);
logger.warn("Subsribe category=configurator, but notifed non-configurator urls. may be registry bug. unexcepted url: " + url);
}
}
if (result != null) {
urls = result;
}
this.configurators = RegistryDirectory.toConfigurators(urls);
List> exporters = new ArrayList>(bounds.values());
for (ExporterChangeableWrapper> exporter : exporters){
Invoker> invoker = exporter.getOriginInvoker();
final Invoker> originInvoker ;
if (invoker instanceof InvokerDelegete){
originInvoker = ((InvokerDelegete>)invoker).getInvoker();
}else {
originInvoker = invoker;
}
URL originUrl = RegistryProtocol.this.getProviderUrl(originInvoker);
URL newUrl = getNewInvokerUrl(originUrl, urls);
if (! originUrl.equals(newUrl)){
RegistryProtocol.this.doChangeLocalExport(originInvoker, newUrl);
}
}
}
private URL getNewInvokerUrl(URL url, List urls){
List localConfigurators = this.configurators; // local reference
// 合并override参数
if (localConfigurators != null && localConfigurators.size() > 0) {
for (Configurator configurator : localConfigurators) {
url = configurator.configure(url);
}
}
return url;
}
}
public static class InvokerDelegete extends InvokerWrapper{
private final Invoker invoker;
/**
* @param invoker
* @param url invoker.getUrl返回此值
*/
public InvokerDelegete(Invoker invoker, URL url){
super(invoker, url);
this.invoker = invoker;
}
public Invoker getInvoker(){
if (invoker instanceof InvokerDelegete){
return ((InvokerDelegete)invoker).getInvoker();
} else {
return invoker;
}
}
}
/**
* exporter代理,建立返回的exporter与protocol export出的exporter的对应关系,在override时可以进行关系修改.
*
* @author chao.liuc
*
* @param
*/
private class ExporterChangeableWrapper implements Exporter{
private Exporter exporter;
private final Invoker originInvoker;
public ExporterChangeableWrapper(Exporter exporter, Invoker originInvoker){
this.exporter = exporter;
this.originInvoker = originInvoker;
}
public Invoker getOriginInvoker() {
return originInvoker;
}
public Invoker getInvoker() {
return exporter.getInvoker();
}
public void setExporter(Exporter exporter){
this.exporter = exporter;
}
public void unexport() {
String key = getCacheKey(this.originInvoker);
bounds.remove(key);
exporter.unexport();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy