SpringBoot采用Java配置类的方式配置Nacos,动态注册微服务IP

简介: 本文是采用Java配置类的方式配置微服务的Nacos服务注册,并动态的配置spring.cloud.discovery.ip属性以打到微服务内网穿透注册至Nacos注册中心。

采用Java配置类的方式配置Nacos,动态注册微服务IP

关键词:SpringBoot、SpringCloud、Nacos、内网穿透、微服务、注册中心、Java配置类、动态IP

一、问题

最近开发项目遇到一个挺恶心的问题,就是云服务器的内网穿透问题。大家知道采用nacos注册中心的时候,微服务会向注册中心注册自己的服务,同时提供自己的IP供其他微服务来访问。下图展示了微服务向注册中心注册时的服务列表。

image-20220710005133910.png

在这个列表的右边点击详情可以看到具体注册的微服务详细信息,如下图就是微服务pizhiku-resources-9500的具体注册信息。

image-20220710010037706.png

这个是微服务的情况,我又在不同的云服务提供商的服务器上启动了一个微服务pizhiku-resources-file-upload-9505

image-20220710010621410.png

可以看到这两个微服务都是向注册中心注册的自己的内网IP,所以虽然在注册中心看到了微服务,但是其他微服务通过网关是无法访问的。网关配置:

image-20220710010907059.png

二、解决

这里我直接放解决方法,详细原理会在下文阐述。

1、在你的云服务器上启动一个Nginx,并添加以下配置:

server {
    # ....
    # 返回访问者的IP
     location /getIp{
            return 200 "$remote_addr";
      }
}

2、在微服务中注释掉yml里服务发现的相关配置:

这里的配置中心在后面配置类用到了,当然也可以自己定义自定义配置。

spring:
  application:
    name: pizhiku-resources-9500
  profiles:
    # dev test prod
    active: dev
  cloud:
    nacos:
#      discovery:
#        server-addr: 120.***.***.77:8848
#        namespace: b9134034-bca4-4979-bc14-f9e7de10924a
    # 配置中心
      config:
        server-addr: 120.***.***.77:8848
        file-extension: yaml
        namespace: b9134034-bca4-4979-bc14-f9e7de10924a
        max-retry: 10

3、在微服务中添加以下配置类:

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

/**
 * @author IPMan
 * @description: Nacos服务发现配置类
 * @date 2022/7/10
 */
@Configuration
public class NacosDiscoveryConfig {
    /**
     * nacosConfigServerAaddr yml中配置的nacos配置中心地址
     */
    @Value("${spring.cloud.nacos.config.server-addr}")
    String nacosConfigServerAaddr;
    /**
     * nacosConfignamespace yml中配置的nacos配置中心命名空间
     */
    @Value("${spring.cloud.nacos.config.namespace}")
    String nacosConfignamespace;
    /**
     * getServerInternetIP 通过Nginx获取本机外网IP,需要Nginx配合配置
     * @author IPMan
     * @date 2022/7/10
     *
     * @return java.lang.String 返回本机外网IP
     */
    private String getServerInternetIP(){
        //通过配置中心地址构造查询IP请求地址
        String url="http://"+nacosConfigServerAaddr.split(":")[0]+"/getIp";
        //调试输出,这里不推荐err的方式输出,这样仅为测试使用,推荐采用日志实现或者不输出
        System.err.println(url);
        //外网IP
        String internetIP="";
        //这里一步完成了,构造一个RestTemplate对象,通过对指定URL执行GET请求来获取响应实体
        ResponseEntity<String> response =
                new RestTemplate()
                        .getForEntity(url, String.class);
        //从响应实体对象中获取内容
        internetIP = response.getBody();
        //调试输出,这里不推荐err的方式输出,这样仅为测试使用,推荐采用日志实现或者不输出
        System.err.println(internetIP);
        return internetIP;
    }

    /**
     * nacosProperties Nacos 服务发现配置类,代替yml中spring.cloud.nacos.discovery:配置
     * @author IPMan
     * @date 2022/7/10
     *
     * @return com.alibaba.cloud.nacos.NacosDiscoveryProperties
     */
    @Bean
    public NacosDiscoveryProperties nacosProperties() {
        //new一个nacos服务发现配置对象
        NacosDiscoveryProperties properties = new NacosDiscoveryProperties();
        //设置发现注册的IP,即注册中心详情中的IP,这里很关键,默认是Inet4Address.getLocalHost(),即如果包含子网,则获取的是子网IP
        properties.setIp(getServerInternetIP());
        //设置注册中心地址
        properties.setServerAddr(nacosConfigServerAaddr);
        //设置注册中心命名空间
        properties.setNamespace(nacosConfignamespace);
        return properties;
    }

    /**
     * nacosServiceDiscovery nacos 服务发现对象,这个对象构造完成后是无法设置配置的
     * @author IPMan
     * @date 2022/7/10
     *
     * @param discoveryProperties com.alibaba.cloud.nacos.NacosDiscoveryProperties
     * @param nacosServiceManager com.alibaba.cloud.nacos.NacosServiceManager
     * @return com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery
     */
    @Bean
    public NacosServiceDiscovery nacosServiceDiscovery(
            NacosDiscoveryProperties discoveryProperties,
            NacosServiceManager nacosServiceManager) {
        return new NacosServiceDiscovery(discoveryProperties, nacosServiceManager);
    }
}

4、保存编译运行

控制台输出:

image-20220710014951807.png

注册中心:

image-20220710015634975.png

如果运行在云服务器上:

image-20220710015602936.png

至此问题解决

三、原理

核心就是要让SpringBoot在加载Nacos服务发现配置的时候是动态加载值,而不是固定死值。

核心配置spring.cloud.nacos.discovery.ip:

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 120.***.77:8848
        namespace: b9134034-bca4-4979-bc14-f9e7de10924a
        ip: ***.***.***.***

这里的实现方法有很多。

  • 通过java -jar -D** 参数传入值
  • 通过.addListeners(new AfterConfigListener());添加spring事件监听器,并设置System.setProperty("spring.cloud.nacos.discovery.ip", internetIP);属性
  • 等待其他方法

-D方式吧,其实很常用,但是如果是多服务器运行的时候,你要配个服务器都手动输入-D参数,当然可以通过自动化部署框架或脚本完成。

第二种采用监听器的方式,详细网址:

【踩坑日记】使用公网ip向nacos注册服务 - 掘金 (juejin.cn)

这种方式确实能够完成,我之前也是使用这种方式,但是不舒服啊,没办法读取yml配置的,也就是说其实他还是写死了的。

所有有了上文采用java配置类的方式配置nacos的想法。

然而网上很多文章包括官方文档都是采用yml或者原生nacosSDK方式连接。

没有找到采用Java配置类的方式配置nacos(官方文档和github我没用细看,粗略看了一下可能有的地方确实没有相关介绍)。

原理就是nacos启动配置时要配置NacosDiscoveryProperties配置类,

image-20220710023324307.png

那么这个东西是怎么找到的呢?

可以这样找:

按住ctrl+鼠标左键点击响应的配置

image-20220710023701998.png

然后就进到配置这个属性的类中

image-20220710023803123.png

翻到最上面,单击类前的小图标,选择导航到SpringBean声明

image-20220710023854246.png

这时候就可以看到那里声明了这个类

image-20220710023955974.png

单击这个类就可以找到相关的自动配置类NacosDiscoveryAutoConfiguration

image-20220710024114790.png

上面这个NacosDiscoveryProperties配置类的Bean是可以点出响应的set方法的

image-20220710024212050.png

这样就可以采用Java配置类的方式配置nacos配置。

同理所有包含spring开头包的yml配置都可以这样找到配置类。

这是倒着找,其实正常如果熟悉springBoot框架加载流程的同学就会直接去找XXXAutoConfiguration,所有带默认的配置基本上都是有一个自动配置类,直接打开就可以看到可以配哪些属性、怎么配。本质上是yml给这些配置类对象的属性赋值。

四、收获

这次探索主要还是自己对springboot框架不熟悉,其实最开始想到了他肯定是有个XXXAutoConfiguration自动配置类,但是双shift搜索nacos的时候有一堆自动配置类:

image-20220710024802586.png

现在看来一个一个看应该是能找到的,因为见名知意嘛,yml的discovery就是nacosDiscovery相关的配置类么。

还是要去真实过几遍框架的流程,只会用不知道原理遇到奇怪的问题不好解决,也不利于个人发展。因为代码都不复杂,核心的是思想,思想很重要。

遇到问题还是要多搜索之后再去询问,因为其实某度哇、某些开发者平台上能找到的问题,都不是问题。官方文档上写的有的也不能叫做问题,前者有具体的解决方案,后者只能说没有仔细学习文档。

待常规方法搜索找不到答案的时候,再求助于真实开发的人,因为人类很大一部分智慧是保存在每个具体人的大脑中,而不是写在书上网上,这叫群体流体智慧。这就是所谓的经验

所以我们再准备回答他人提出的问题的时候,就应该假定对方以及在常规搜索路径上无法获取答案,才会求助与你。而不是像一个键盘侠一样恢复个“没营养的问题”、“百度上有”,之类的不负责任的话。更有甚者随便截个类名就说自己找到了,也不敢发文章,仔细问才发现他连文档都没看过。这样的网络键盘侠的行为,我没要引以为戒。

目录
相关文章
|
Java 数据库连接 API
Java 8 + 特性及 Spring Boot 与 Hibernate 等最新技术的实操内容详解
本内容涵盖Java 8+核心语法、Spring Boot与Hibernate实操,按考试考点分类整理,含技术详解与代码示例,助力掌握最新Java技术与应用。
342 2
|
Java 数据库连接 API
Java 对象模型现代化实践 基于 Spring Boot 与 MyBatis Plus 的实现方案深度解析
本文介绍了基于Spring Boot与MyBatis-Plus的Java对象模型现代化实践方案。采用Spring Boot 3.1.2作为基础框架,结合MyBatis-Plus 3.5.3.1进行数据访问层实现,使用Lombok简化PO对象,MapStruct处理对象转换。文章详细讲解了数据库设计、PO对象实现、DAO层构建、业务逻辑封装以及DTO/VO转换等核心环节,提供了一个完整的现代化Java对象模型实现案例。通过分层设计和对象转换,实现了业务逻辑与数据访问的解耦,提高了代码的可维护性和扩展性。
505 1
|
Java 调度 流计算
基于Java 17 + Spring Boot 3.2 + Flink 1.18的智慧实验室管理系统核心代码
这是一套基于Java 17、Spring Boot 3.2和Flink 1.18开发的智慧实验室管理系统核心代码。系统涵盖多协议设备接入(支持OPC UA、MQTT等12种工业协议)、实时异常检测(Flink流处理引擎实现设备状态监控)、强化学习调度(Q-Learning算法优化资源分配)、三维可视化(JavaFX与WebGL渲染实验室空间)、微服务架构(Spring Cloud构建分布式体系)及数据湖建设(Spark构建实验室数据仓库)。实际应用中,该系统显著提升了设备调度效率(响应时间从46分钟降至9秒)、设备利用率(从41%提升至89%),并大幅减少实验准备时间和维护成本。
612 0
|
Java API 微服务
Java 21 与 Spring Boot 3.2 微服务开发从入门到精通实操指南
《Java 21与Spring Boot 3.2微服务开发实践》摘要: 本文基于Java 21和Spring Boot 3.2最新特性,通过完整代码示例展示了微服务开发全流程。主要内容包括:1) 使用Spring Initializr初始化项目,集成Web、JPA、H2等组件;2) 配置虚拟线程支持高并发;3) 采用记录类优化DTO设计;4) 实现JPA Repository与Stream API数据访问;5) 服务层整合虚拟线程异步处理和结构化并发;6) 构建RESTful API并使用Springdoc生成文档。文中特别演示了虚拟线程配置(@Async)和StructuredTaskSco
1259 0
|
监控 安全 Java
Java 开发中基于 Spring Boot 3.2 框架集成 MQTT 5.0 协议实现消息推送与订阅功能的技术方案解析
本文介绍基于Spring Boot 3.2集成MQTT 5.0的消息推送与订阅技术方案,涵盖核心技术栈选型(Spring Boot、Eclipse Paho、HiveMQ)、项目搭建与配置、消息发布与订阅服务实现,以及在智能家居控制系统中的应用实例。同时,详细探讨了安全增强(TLS/SSL)、性能优化(异步处理与背压控制)、测试监控及生产环境部署方案,为构建高可用、高性能的消息通信系统提供全面指导。附资源下载链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)。
2672 0
|
druid Java 数据库连接
深入学习SpringBoot微服务框架
深入学习SpringBoot微服务框架
深入学习SpringBoot微服务框架
|
9月前
|
JavaScript Java 关系型数据库
基于springboot的项目管理系统
本文探讨项目管理系统在现代企业中的应用与实现,分析其研究背景、意义及现状,阐述基于SSM、Java、MySQL和Vue等技术构建系统的关键方法,展现其在提升管理效率、协同水平与风险管控方面的价值。