专栏首页龙首琴剑庐解决 Spring Cloud Consul 在 Tomcat 容器中服务注册问题

解决 Spring Cloud Consul 在 Tomcat 容器中服务注册问题

问题

Spring Cloud Consul 2.1.x 在 Tomcat 容器中没有注册服务,但是在本地开发的时候是没问题的。

分析

Spring Cloud 2.1.x 注册服务, 是通过发布org.springframework.boot.web.context.WebServerInitializedEvent 事件实现的, 参考 org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationListener

  • org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationListener
@Override
	public void onApplicationEvent(ApplicationEvent applicationEvent) {
		if (applicationEvent instanceof WebServerInitializedEvent) {
			WebServerInitializedEvent event = (WebServerInitializedEvent) applicationEvent;

			ApplicationContext context = event.getApplicationContext();
			if (context instanceof ConfigurableWebServerApplicationContext) {
				if ("management".equals(
						((ConfigurableWebServerApplicationContext) context).getServerNamespace())) {
					return;
				}
			}
			this.autoServiceRegistration.setPortIfNeeded(event.getWebServer().getPort());
			this.autoServiceRegistration.start();
		}
	}

该事件仅在内嵌 Tomcat 中生效,参考 org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext, 而通过 Tomcat 容器启动服务时监听不到该事件。

  • org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext
  protected void finishRefresh() {
    super.finishRefresh();
    WebServer webServer = this.startWebServer();
	 // 这里在 内嵌Tomcat 启动后,webServer 不为 null ,发布 ServletWebServerInitializedEvent 事件,触发 ConsulAutoServiceRegistrationListener 注册服务
	// 这里在 Tomcat 容器启动服务 后,webServer 是 null 的,因此导致 ConsulAutoServiceRegistrationListener 接收不到对应的事件,从而无法服务注册
    if (webServer != null) {
      this.publishEvent(new ServletWebServerInitializedEvent(webServer, this));
    }
  }

解决

增加一个 ApplicationListener 监听 ApplicationReadyEvent, 在应用启动准备好后注册服务。 逻辑参考 org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationListener

import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.cloud.consul.ConditionalOnConsulEnabled;
import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties;
import org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistration;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * Spring Cloud 2.1 注册服务, 通过发布 {@link org.springframework.boot.web.context.WebServerInitializedEvent} 事件实现的, 参考 {@link
 * org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationListener}。
 *
 * <p>
 * 该事件仅在内嵌 Tomcat 中生效,参考 {@link org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext}, 而通过
 * Tomcat 容器启动服务时监听不到该事件。
 * </p>
 *
 * @author Sven Augustus
 */
@Component
@ConditionalOnConsulEnabled
@RequiredArgsConstructor
public class ConsulAutoServiceRegistrationInitializerListener implements ApplicationListener<ApplicationReadyEvent> {

  private final ConsulAutoServiceRegistration consulAutoServiceRegistration;
  private final ConsulDiscoveryProperties properties;

  @Override
  public void onApplicationEvent(ApplicationReadyEvent event) {
    consulAutoServiceRegistration.start();
  }

}

by Sven Augustus https://my.oschina.net/langxSpirit

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 基于复杂方案OWSAP CsrfGuard的CSRF安全解决方案(适配nginx + DWR)

    1、什么是CSRF? 已经有很多博文讲解其过程和攻击手段,在此就不重复了。 O(∩_∩)O 不清楚的同学,请自行搜索或按链接去了解: http://blog...

    斯武丶风晴
  • Java标准I/O流编程一览笔录

    Java标准I/O知识体系图: ? 1、I/O是什么? I/O 是Input/Output(输入、输出)的简称,输入流可以理解为向内存输入,输出流是从内存输出。...

    斯武丶风晴
  • 图解Linux的IO模型和相关技术

    如果出现了很多的客户端连接,比如1000个,那么应用程序就会启用1000个进程或线程阻塞等待。此时会出现性能问题:

    斯武丶风晴
  • Spring 中的如何自定义事件处理(Custom Event)

    Jerry Wang
  • Spring Boot + Spring Cloud 构建微服务系统(十):配置中心(Spring Cloud Bus)

    我们在上一篇讲到,Spring Boot程序只在启动的时候加载配置文件信息,这样在GIT仓库配置修改之后,虽然配置中心服务器能够读取最新的提交信息,但是配置中心...

    朝雨忆轻尘
  • Python——用socket和线程实现

    全双工:是指在发送数据的同时也能够接收数据,两者同步进行,这好像我们平时打电话一样,说话的同时也能够听到对方的声音。

    py3study
  • CoreOS配置Docker 2375端口 原

    bdcn
  • 【python】【Djang】GPS/北斗串口数据实时定位百度地图

    本项目为从串口读取GPS/北斗设备接收数据,进行处理后使用百度地图api实时显示定位。

    一点儿也不潇洒
  • 二十五块DIY 带屏幕可远程的温湿度传感器

    小米的温湿度传感器坏了,不带屏幕。就一个硬币大小,还得配合小米网关使用。。买不起我就自己做一个。。 打开神奇的拼多多,买一个神器开发板可以连接wifi的Node...

    KurtNiu
  • JS截取字符串常用方法

    功能:字符串截取,比如想从"MinidxSearchEngine”中得到"Minidx”就要用到substring(0,6)

    山河木马

扫码关注云+社区

领取腾讯云代金券