Spring Boot 应用打 WAR 包后无法注册到 Nacos怎么办

你好,我是柳岸花开。

在微服务架构中,服务注册与发现是至关重要的一环。Nacos 作为阿里巴巴开源的注册中心,能够很好地满足这一需求。然而,在将 Spring Boot 应用打包成 WAR 部署到外部服务器时,可能会遇到服务无法注册到 Nacos 的问题。本文将详细讲解这一问题的解决方案。

问题描述

在开发过程中,通常使用 JAR 包运行 Spring Boot 应用,这种方式下,服务注册到 Nacos 通常没有问题。然而,当我们将 Spring Boot 应用打包成 WAR 并部署到外部 Tomcat 服务器时,可能会遇到服务无法注册到 Nacos 的情况。其原因主要是应用获取不到正确的服务器端口。

解决方案

为了在 WAR 包部署时正确地注册服务到 Nacos,我们需要动态地获取实际使用的服务器端口,并将其设置到 Nacos 的服务注册中。以下是一个具体的实现代码:

import com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.Query;
import java.lang.management.ManagementFactory;
import java.util.Set;

/**
 * 解决 Spring Boot 应用打 WAR 包后无法注册到 Nacos 的问题
 * 通过动态获取服务器端口并注册到 Nacos
 */
@Slf4j
@ConditionalOnProperty(prefix = "project.deploy", name = "mode", havingValue = "war")
@Component
public class NacosConfig implements ApplicationRunner {

    @Autowired
    private NacosAutoServiceRegistration registration;

    @Value("${server.port:8080}")
    Integer port;

    @Override
    public void run(ApplicationArguments args) {
        if (registration != null && port != null) {
            Integer serverPort = port;
            try {
                serverPort = new Integer(getServerPort());
            } catch (Exception e) {
                log.warn("getServerPort warn", e);
                log.info("getServerPort fail, use the config-file's port {}", port);
            }
            registration.setPort(serverPort);
            registration.start();
        }
    }

    /**
     * 获取实际使用的服务器端口
     */
    public String getServerPort() throws Exception {
        MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> objectNames = beanServer.queryNames(new ObjectName("*:type=Connector,*"), Query.match(Query.attr("protocol"), Query.value("HTTP/1.1")));
        String port = objectNames.iterator().next().getKeyProperty("port");
        log.debug("getServerPort {}", port);
        return port;
    }
}

代码解析

1. 类与注解

@Slf4j
@ConditionalOnProperty(prefix = "project.deploy", name = "mode", havingValue = "war")
@Component
public class NacosConfig implements ApplicationRunner {
  • @Slf4j:Lombok 提供的注解,用于生成日志记录器。
  • @ConditionalOnProperty:只有在 project.deploy.mode 属性值为 war 时,才会创建这个 NacosConfig bean。
  • @Component:标记为 Spring 的组件,使其能够被 Spring 扫描和管理。
  • ApplicationRunner:实现该接口的 run 方法将在应用启动时运行。

2. 自动注入与配置

@Autowired
private NacosAutoServiceRegistration registration;

@Value("${server.port:8080}")
Integer port;
  • @Autowired:注入 Nacos 的服务注册类 NacosAutoServiceRegistration
  • @Value:注入配置文件中的端口号,如果未配置则默认使用 6888 端口。

3. 启动时设置端口

@Override
public void run(ApplicationArguments args) {
    if (registration != null && port != null) {
        Integer serverPort = port;
        try {
            serverPort = new Integer(getServerPort());
        } catch (Exception e) {
            log.warn("getServerPort warn", e);
            log.info("getServerPort fail, use the config-file's port {}", port);
        }
        registration.setPort(serverPort);
        registration.start();
    }
}
  • 在应用启动时尝试获取实际使用的服务器端口,如果获取失败则使用配置文件中的端口。
  • 将端口设置到 Nacos 的服务注册中,并启动服务注册。

4. 获取实际端口

public String getServerPort() throws Exception {
    MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
    Set<ObjectName> objectNames = beanServer.queryNames(new ObjectName("*:type=Connector,*"), Query.match(Query.attr("protocol"), Query.value("HTTP/1.1")));
    String port = objectNames.iterator().next().getKeyProperty("port");
    log.debug("getServerPort {}", port);
    return port;
}
  • 通过 JMX 管理接口获取实际使用的 HTTP 端口。

总结

通过上述代码,我们可以实现在 Spring Boot 应用启动时,动态获取并设置 Nacos 注册的端口号。这对于在不同环境中部署应用非常有用,可以避免硬编码端口号带来的问题。同时,结合 Nacos 的服务注册与发现功能,可以更加灵活地管理微服务架构中的各个服务。

希望本文能对大家有所帮助,如果有任何疑问或建议,欢迎在下方留言交流。

👇关注我,下期了解👇

Spring配置类源码深度解析

回复 222,获取Java面试题合集

关于我

一枚爱折腾的Java程序猿,专注Spring干货。把路上的问题记录下来,帮助那些和我一样的人。

好奇心强,喜欢并深入研究古天文。

崇尚 个人系统创建,做一些时间越长越有价值的事情。思考 把时间留下来 又 每刻都是新的。

本文由mdnice多平台发布

相关推荐
ok!ko2 小时前
设计模式之原型模式(通俗易懂--代码辅助理解【Java版】)
java·设计模式·原型模式
2402_857589362 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
吾爱星辰3 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
哎呦没3 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
编程、小哥哥4 小时前
netty之Netty与SpringBoot整合
java·spring boot·spring
IT学长编程5 小时前
计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·玩具租赁系统
莹雨潇潇5 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
杨哥带你写代码5 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
郭二哈6 小时前
C++——模板进阶、继承
java·服务器·c++
A尘埃6 小时前
SpringBoot的数据访问
java·spring boot·后端