Dubbo系列讲解之服务注册【3万字长文分享】

【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】

**开源地址:https://docs.qq.com/doc/DSmxTbFJ1cmN1R2dB **

此时突然想起来我们在进行扫包的一系列操作之前,貌似注册了一个监听器,是不是可以从监听器入手呢?

进入到前面注册的DubboBootstrapApplicationListener监听器中

public class DubboBootstrapApplicationListener extends OneTimeExecutionApplicationContextEventListener

implements Ordered {

/**

  • The bean name of {@link DubboBootstrapApplicationListener}

  • @since 2.7.6

*/

public static final String BEAN_NAME = “dubboBootstrapApplicationListener”;

private final DubboBootstrap dubboBootstrap;

public DubboBootstrapApplicationListener() {

this.dubboBootstrap = DubboBootstrap.getInstance();

}

@Override

public void onApplicationContextEvent(ApplicationContextEvent event) {

if (event instanceof ContextRefreshedEvent) {

onContextRefreshedEvent((ContextRefreshedEvent) event);

} else if (event instanceof ContextClosedEvent) {

onContextClosedEvent((ContextClosedEvent) event);

}

}

private void onContextRefreshedEvent(ContextRefreshedEvent event) {

dubboBootstrap.start();

}

private void onContextClosedEvent(ContextClosedEvent event) {

dubboBootstrap.stop();

}

@Override

public int getOrder() {

return LOWEST_PRECEDENCE;

}

}

可以看到,该监听器监听了容器的容器的刷新和关闭,我们前面的操作已经将ServiceBean注入到了ioc容器中,根据ioc的容器初始化的几个周期,可以知道在Refreshd容器时,我们所有的服务提供者对应的ServiceBean已经全部装载到了容器中。

继续往下,当产生ContextRefreshedEvent事件时,调用了onContextRefreshedEvent方法,该方法中调用dubboBootstrap.start();

到这里,跟Spring相关的东西已经走完了,下面做一个总结

  • 通过Spring Boot的自动装配或@EnableDubbo注解自动注入一个ServiceAnnotationBeanPostProcessor传入需要扫描的包的路径

  • 注册了一个``DubboBootstrapApplicationListener`监听

  • 根据BeanPostProcessor的特性,调用postProcessBeanDefinitionRegistry方法,根据传入的扫包路径进行扫描,然后将所有的标注了@Service注解的bean注入到ioc容器中

  • 继续扫描包,获得标注了Service/DubboService等注解的所有BeanDefinitionHolders

  • 遍历BeanDefinitionHolders,解析出每个BeanDefinition中的接口,标注的注解,及注解上定义的参数等。

  • 通过解析出来的一系列信息生成一个ServiceBean.然后将ServiceBean注入到ioc容器中。

  • 同时在ServiceBean的父类AbstractConfig中,会存在一个标注了@PostConstruct注解的方法,它会在bean初始化完成之后,将当前bean保存到一个ConfigManager对象中,它dubbo环境中是一个单例的存在。

  • 在Spring进行Refresh容器时,会触发一个事件,调用dubboBootstrap.start();方法,启动

接下来就真正的进入到Dubbo的服务发布,注册的世界,一探究竟吧

Dubbo的服务注册与发布


在进入start()方法之前,首先需要看看dubboBootstrap的初始化过程,它是一个单例的对象,直接进入DubboBootstrap的构造方法

private DubboBootstrap() {

configManager = ApplicationModel.getConfigManager();

environment = ApplicationModel.getEnvironment();

DubboShutdownHook.getDubboShutdownHook().register();

ShutdownHookCallbacks.INSTANCE.addCallback(new ShutdownHookCallback() {

@Override

public void callback() throws Throwable {

DubboBootstrap.this.destroy();

}

});

}

可以看到,初始化时构建了configManager和environment,其中configManager主要用于管理Dubbo中的所有配置。Environment展示先不关注

根据以上的分析,我们现在进入到start()方法

public DubboBootstrap start() {

// 已经启动过后,就不用再次启动了

if (started.compareAndSet(false, true)) {

ready.set(false);

// 初始化方法,就是检查一些配置,启动配置中心等等

initialize();

if (logger.isInfoEnabled()) {

logger.info(NAME + " is starting…");

}

// 1. export Dubbo Services

// 真正执行发布服务的方法

exportServices();

// Not only provider register

if (!isOnlyRegisterProvider() || hasExportedServices()) {

// 2. export MetadataService

exportMetadataService();

//3. Register the local ServiceInstance if required

registerServiceInstance();

}

referServices();

if (asyncExportingFutures.size() > 0) {

new Thread(() -> {

try {

this.awaitFinish();

} catch (Exception e) {

logger.warn(NAME + " exportAsync occurred an exception.");

}

ready.set(true);

if (logger.isInfoEnabled()) {

logger.info(NAME + " is ready.");

}

}).start();

} else {

ready.set(true);

if (logger.isInfoEnabled()) {

logger.info(NAME + " is ready.");

}

}

if (logger.isInfoEnabled()) {

logger.info(NAME + " has started.");

}

}

return this;

}

调用了exportServices方法进行了服务的发布和注册,调用referServices方法进行服务的发现,服务发现将留到下一篇去,今天只对服务的注册进行探索。

进入到exportServices方法

private void exportServices() {

configManager.getServices().forEach(sc -> {

// TODO, compatible with ServiceConfig.export()

ServiceConfig serviceConfig = (ServiceConfig) sc;

serviceConfig.setBootstrap(this);

if (exportAsync) {

ExecutorService executor = executorRepository.getServiceExporterExecutor();

Future<?> future = executor.submit(() -> {

sc.export();

exportedServices.add(sc);

});

asyncExportingFutures.add(future);

} else {

sc.export();

exportedServices.add(sc);

}

});

}

遍历我们在Spring Boot环节时添加到configManager的所有ServiceConfig,将当前的对象传入到ServiceConfig中,同步或异步调用ServiceConfig的export方法。

进入到export方法

public synchronized void export() {

if (!shouldExport()) {

return;

}

if (bootstrap == null) {

bootstrap = DubboBootstrap.getInstance();

bootstrap.init();

}

checkAndUpdateSubConfigs();

//init serviceMetadata

serviceMetadata.setVersion(version);

serviceMetadata.setGroup(group);

serviceMetadata.setDefaultGroup(group);

serviceMetadata.setServiceType(getInterfaceClass());

serviceMetadata.setServiceInterfaceName(getInterface());

serviceMetadata.setTarget(getRef());

if (shouldDelay()) {

DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);

} else {

doExport();

}

exported();

}

该方法算是Dubbo服务发布的入口流程方法了。

  • 判断是否应该发布本服务

  • 如果DubboBootstrap对象为null,初始化一个DubboBootstrap对象

  • 检查是否更新存根配置

  • 初始化ServiceMetadata,将注入Bean时初始化的一些参数保存到serviceMetadata中

  • 延时或同步调用doExport

进入doExport

protected synchronized void doExport() {

if (unexported) {

throw new IllegalStateException(“The service " + interfaceClass.getName() + " has already unexported!”);

}

if (exported) {

return;

}

exported = true;

if (StringUtils.isEmpty(path)) {

path = interfaceName;

}

doExportUrls();

}

做了一系列判断,标识等初始化之后,再调用doExportUrls方法

private void doExportUrls() {

ServiceRepository repository = ApplicationModel.getServiceRepository();

ServiceDescriptor serviceDescriptor = repository.registerService(getInterfaceClass());

repository.registerProvider(

getUniqueServiceName(),

ref,

serviceDescriptor,

this,

serviceMetadata

);

List registryURLs = ConfigValidationUtils.loadRegistries(this, true);

for (ProtocolConfig protocolConfig : protocols) {

String pathKey = URL.buildKey(getContextPath(protocolConfig)

.map(p -> p + “/” + path)

.orElse(path), group, version);

// In case user specified path, register service one more time to map it to path.

repository.registerService(pathKey, interfaceClass);

// TODO, uncomment this line once service key is unified

serviceMetadata.setServiceKey(pathKey);

doExportUrlsFor1Protocol(protocolConfig, registryURLs);

}

}

  • 获取到一个ServiceRepository,根据前面分析的经验,可以看出这里得到的就是一个ServiceRepository对象。

  • 根据服务的接口名称和字节码封装一个ServiceDescriptor保存到repository的services中。并返回ServiceDescriptor

  • 调用registerProvider方法,将唯一服务名,服务的Provider,serviceDescriptor,当前对象,ServiceMetadata等传入方法。

解析注册中心的URLregistryURLs,这里返回的是如下的URL

registry://192.168.100.127:2181/org.apache.dubbo.registry.RegistryService?application=spring-cloud-alibaba-boot-dubbo-provider&default=true&dubbo=2.0.2&pid=48053&preferred=true&qos.enable=false&registry=zookeeper&release=2.7.7&timeout=10000&timestamp=1598411022992

  • 遍历protocols,根据遍历到的协议拼接成不同的pathKey,调用registerService进行注册,保存服务源信息

  • 根据不同的协议,调用doExportUrlsFor1Protocol方法进行注册

进入registerProvider方法,该方法会将传入的对象构建成一个ProviderModel对象。保存到相应的集合中,同时在ProviderModel对象初始化时,会调用将该接口的所有方法遍历,构建成一个ProviderMethodModel保存到methods中。

然后进入到doExportUrlsFor1Protocol,方法过长,这里就不贴代码了。其主要完成了以下功能

  • 根据初始化ServiceBean时传入的各个参数,封装成一个map

  • 获取当前服务器的host

  • 获取当前服务需要监听的port

  • 根据封装的参数,协议,host,port构建一个URL

  • 发布一个本地服务-injvm

  • 获取到配置的注册中心的URL,可以存在多个注册中心,这就是Dubbo对多注册中心的支持

  • 添加注册中心的URL的参数

  • 生成monitor的URL

  • 再次封装发布服务的URL的参数

  • 通过Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));将当前服务的url作为参数添加到注册中心的url上,然后使用registryURL和当前服务接口字节码,服务实现构建一个invoker,这是一个属于注册中心的invoker;

  • 使用Invoker和当前的ServiceConfig构建一个 DelegateProviderMetaDataInvoker对象

  • 调用Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);进行服务的发布

  • 将返回的exporter添加到exporters中

接下来看看是怎么获取到Invoker的,根据我们的SPI的知识,在没有参数中没有指定扩展点时,会使用默认@SPI注解上默认指定的扩展点,由于在ProxyFactory类上的注解为@SPI(“javassist”),所以可以知道这里获取到的扩展点为JavassistProxyFactory的对象,在进入JavassistProxyFactory的getInvoker()方法之前,根据我们学习SPI的知识,或许该扩展点存在一些包装,这里就不详细说明了,主要讲服务发布的主要流程。进入该类的getInvoker()方法。

public Invoker getInvoker(T proxy, Class type, URL url) {

// TODO Wrapper cannot handle this scenario correctly: the classname contains ‘$’

final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf(‘$’) < 0 ? proxy.getClass() : type);

return new AbstractProxyInvoker(proxy, type, url) {

@Override

protected Object doInvoke(T proxy, String methodName,

Class<?>[] parameterTypes,

Object[] arguments) throws Throwable {

return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);

}

};

}

根据传入的服务接口的class对象,动态生成的一个包装器,该包装器继承了Wrapper了,重写了invokeMethod()方法。重写方法如下

public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {

com.wangx.spring.cloud.alibaba.provider.HelloServiceImpl w;

try {

w = ((com.wangx.spring.cloud.alibaba.provider.HelloServiceImpl) $1);

} catch (Throwable e) {

throw new IllegalArgumentException(e);

}

try {

if (“hello”.equals($2) && $3.length == 1) {

return ($w) w.hello((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.wangx.spring.cloud.alibaba.provider.HelloServiceImpl.”);

}

所以,当AbstractProxyInvoker的doInvoke方法被调用的时候,会直接执行被传入服务提供者的具体方法。这样做的好处就是在服务启动时就将方法调用准备好,在被远程调用时,直接通过引用调用,而不需要通过反射调用。提高性能。回到doExportUrlsFor1Protocol方法,根据返回的invoker和当前对象包装一个DelegateProviderMetaDataInvoker对象,接下来调用Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);方法。

现在先来确定PROCTOL的具体实现是什么,PROCTOL是一个自适应的扩展点,它会生成一个Proctol&Adaptie的类,该类实现了Protocol接口,重写了Protocol的export和refer()方法。这里只讨论生成的export方法,如下:

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);

}

该方法会根据传入的invoker对象中的 protocol作为扩展名,获取Protocol的扩展实现,因为我上一步我们传入的是registryURl,根据注解的协议可以知道,通过自适应扩展对象获取到的扩展实现为RegistryProtocol的对象,进入该类的export方法。

public Exporter export(final Invoker originInvoker) throws RpcException {

URL registryUrl = getRegistryUrl(originInvoker);

// url to export locally

URL providerUrl = getProviderUrl(originInvoker);

// Subscribe the override data

// FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call

// the same service. Because the subscribed is cached key with the name of the service, it causes the

// subscription information to cover.

final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);

final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);

overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);

providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);

//export invoker

final ExporterChangeableWrapper exporter = doLocalExport(originInvoker, providerUrl);

// url to registry

final Registry registry = getRegistry(originInvoker);

final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);

// decide if we need to delay publish

boolean register = providerUrl.getParameter(REGISTER_KEY, true);

if (register) {

register(registryUrl, registeredProviderUrl);

}

// register stated url on provider model

registerStatedUrl(registryUrl, registeredProviderUrl, register);

// Deprecated! Subscribe to override rules in 2.6.x or before.

registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);

exporter.setRegisterUrl(registeredProviderUrl);

exporter.setSubscribeUrl(overrideSubscribeUrl);

notifyExport(exporter);

//Ensure that a new exporter instance is returned every time export

return new DestroyableExporter<>(exporter);

}

  • 调用getRegistryUrl(originInvoker);方法获取注册中心的真正的URL,这里会将registry替换成我们配置的zookeeper,如果配置的是nacos,则返回nacos

  • 调用getProviderUrl方法获取服务发布的url,稍后会将该服务发布到注册中心上

  • 调用doLocalExport(originInvoker, providerUrl);发布一个本地服务

  • 调用getRegistry(originInvoker);获取真正配置的注册中心的Registry.

  • 将服务注册到注册中心

进入doLocalExport(originInvoker, providerUrl);方法

private ExporterChangeableWrapper doLocalExport(final Invoker originInvoker, URL providerUrl) {

String key = getCacheKey(originInvoker);

return (ExporterChangeableWrapper) bounds.computeIfAbsent(key, s -> {

Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);

return new ExporterChangeableWrapper<>((Exporter) protocol.export(invokerDelegate), originInvoker);

});

}

首先获取服务的的key,格式如下:

dubbo://192.168.100.127:20880/com.wangx.dubbo.api.HelloService?anyhost=true&application=spring-cloud-alibaba-boot-dubbo-provider&bind.ip=192.168.100.127&bind.port=20880&deprecated=false&dubbo=2.0.2&generic=false&interface=com.wangx.dubbo.api.HelloService&methods=hello&pid=58949&qos.enable=false&release=2.7.7&revision=2.0.1&side=provider&timestamp=1598493906319&version=2.0.1

包含了服务的协议,端口,服务名称,应用名称,版本等信息。将入传入的Invoker和providerUrl构建一个InvokerDelegate类型的对象。并将服务提供者URL赋值为InvokerDelegate对象的url属性,将该对象传入到protocol.export(invokerDelegate)方法中。根据SPI的原理,这里会依赖注入一个Procotol$Adaptive的自适应扩展类,此时传入的是Dubbo协议的URL,所以这里实际会执行的是DubboProtocol中的方法。进入DubboProtocol类中的export方法

public Exporter export(Invoker invoker) throws RpcException {

URL url = invoker.getUrl();

// export service.

String key = serviceKey(url);

DubboExporter exporter = new DubboExporter(invoker, key, exporterMap);

exporterMap.put(key, exporter);

//export an stub service for dispatching event

Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT);

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.”));

}

}

}

openServer(url);

optimizeSerialization(url);

return exporter;

}

  • 根据URL获取一个service的key,构建一个DubboExporter对象,该对象包含了传入的key,invoker,exporterMap等,在invoker中有嵌套了最开始生成的能够实际执行服务提供者方法的代理对象。

  • 将DubboExporter的对象保存到exporterMap集合中。

  • 调用openServer方法发布服务

  • 序列化url

进入openServer(url)

private void openServer(URL url) {

// find server.

String key = url.getAddress();

//client can export a service which’s only for server to invoke

boolean isServer = url.getParameter(IS_SERVER_KEY, true);

if (isServer) {

ProtocolServer server = serverMap.get(key);

if (server == null) {

synchronized (this) {

server = serverMap.get(key);

if (server == null) {

serverMap.put(key, createServer(url));

}

}

} else {

// server supports reset, use together with override

server.reset(url);

}

}

}

刚方法主要双重检查是否存在当前地址的ProtocolServer,不存在创建一个保存到serverMap中。进入createServer方法该方法主要是调用Exchangers.bind(url, requestHandler);方法对地址和端口进行监听,然后转入一个requestHandler对象,当接收到请求时,调用requestHandler对象的reply方法进行处理

这里不再深入到netty网络部分,直接来看看接收到请求的时候,是怎么处理的,进入到reply方法

@Override

public CompletableFuture reply(ExchangeChannel channel, Object message) throws RemotingException {

if (!(message instanceof Invocation)) {

throw new RemotingException(channel, "Unsupported request: "

  • (message == null ? null : (message.getClass().getName() + ": " + message))

  • ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());

}

Invocation inv = (Invocation) message;

Invoker<?> invoker = getInvoker(channel, inv);

// need to consider backward-compatibility if it’s a callback

if (Boolean.TRUE.toString().equals(inv.getObjectAttachments().get(IS_CALLBACK_SERVICE_INVOKE))) {

String methodsStr = invoker.getUrl().getParameters().get(“methods”);

boolean hasMethod = false;

if (methodsStr == null || !methodsStr.contains(“,”)) {

hasMethod = inv.getMethodName().equals(methodsStr);

} else {

String[] methods = methodsStr.split(“,”);

for (String method : methods) {

if (inv.getMethodName().equals(method)) {

hasMethod = true;

break;

}

}

}

if (!hasMethod) {

logger.warn(new IllegalStateException("The methodName " + inv.getMethodName()

  • " not found in callback service interface ,invoke will be ignored."

  • " please update the api interface. url is:"

  • invoker.getUrl()) + " ,invocation is :" + inv);

return null;

}

}

RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());

Result result = invoker.invoke(inv);

return result.thenApply(Function.identity());

}

将接收到的message转成Invocation对象,这是rpc在传输过程中对于调用端的一些参数的封装,包含了服务名,端口,方法名,方法参数等,通过inv获取到invoker,进入getInvoker该方法主要通过inv封装成一个serviceKey,然后通过该serviceKey从exporterMap容器中获取到对应的DubboExporter,然后从该DubboExporter中获取到初始化时传入的invoker回到reply方法,会调用返回的invoker.invoker方法,该invoker中最底层封装了一个最原始的AbstractProxyInvoker的invoker,所以最终会调用到该类型的对象的invoker,如下:

public Result invoke(Invocation invocation) throws RpcException {

try {

Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());

CompletableFuture future = wrapWithFuture(value);

CompletableFuture appResponseFuture = future.handle((obj, t) -> {

AppResponse result = new AppResponse();

if (t != null) {

if (t instanceof CompletionException) {

result.setException(t.getCause());

} else {

result.setException(t);

}

} else {

result.setValue(obj);

}

return result;

});

return new AsyncRpcResult(appResponseFuture, invocation);

} catch (InvocationTargetException e) {

if (RpcContext.getContext().isAsyncStarted() && !RpcContext.getContext().stopAsync()) {

logger.error(“Provider async started, but got an exception from the original method, cannot write the exception back to consumer because an async result may have returned the new thread.”, e);

}

return AsyncRpcResult.newDefaultAsyncResult(null, e.getTargetException(), invocation);

} catch (Throwable e) {

throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);

}

}

然后这里会调用一个doInvoker()方法,这是一个模板方法,正好对应前面创建的如下代码

return new AbstractProxyInvoker(proxy, type, url) {

@Override

protected Object doInvoke(T proxy, String methodName,

Class<?>[] parameterTypes,

Object[] arguments) throws Throwable {

return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);

}

};

所以最终调用wrapper.invokerMethod方法,然后调用对应服务的对应的方法。

到这里服务本地监听和当请求过来时的处理就大致聊完了,接下来重新回到RegistryProtocol类的export方法

进入到register(registryUrl, registeredProviderUrl);方法

private void register(URL registryUrl, URL registeredProviderUrl) {

Registry registry = registryFactory.getRegistry(registryUrl);

registry.register(registeredProviderUrl);

}

这里的registryUrl经过转换,已经变成了我们配置的zokeeper协议的url,所以这里我们将会获得一个ZookeeperRegistry的对象。将registeredProviderUrl传入到register方法中,在进入到ZookeeperRegistry中时,发现并没有register方法,那么只可能存在于它的父类中,在它的父类FailbackRegistry中,我们找到了这个方法,进入

public void register(URL url) {

if (!acceptable(url)) {

logger.info(“URL " + url + " will not be registered to Registry. Registry " + url + " does not accept service of this protocol type.”);

return;

}

super.register(url);

removeFailedRegistered(url);

removeFailedUnregistered(url);

try {

// Sending a registration request to the server side

doRegister(url);

} catch (Exception e) {

Throwable t = e;

// If the startup detection is opened, the Exception is thrown directly.

boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)

&& url.getParameter(Constants.CHECK_KEY, true)

&& !CONSUMER_PROTOCOL.equals(url.getProtocol());

boolean skipFailback = t instanceof SkipFailbackWrapperException;

if (check || skipFailback) {

if (skipFailback) {

t = t.getCause();

}

throw new IllegalStateException("Failed to register " + url + " to registry " + getUrl().getAddress() + ", cause: " + t.getMessage(), t);

} else {

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值