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

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 本文是采用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相关的配置类么。

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

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

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

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

目录
相关文章
|
6天前
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
6天前
|
SpringCloudAlibaba 应用服务中间件 Nacos
【微服务 SpringCloudAlibaba】实用篇 · Nacos配置中心(下)
【微服务 SpringCloudAlibaba】实用篇 · Nacos配置中心
20 0
|
6天前
|
JSON SpringCloudAlibaba Java
【微服务 SpringCloudAlibaba】实用篇 · Nacos配置中心(上)
【微服务 SpringCloudAlibaba】实用篇 · Nacos配置中心
23 1
|
6天前
|
消息中间件 Java 微服务
Java微服务架构实践指南
Java微服务架构实践指南
23 0
|
6天前
|
缓存 NoSQL Java
构建高性能微服务架构:Java后端的实践之路
【5月更文挑战第5天】在当今快速迭代和高并发需求的软件开发领域,微服务架构因其灵活性、可扩展性而受到青睐。本文将深入探讨如何在Java后端环境中构建一个高性能的微服务系统,涵盖关键的设计原则、常用的框架选择以及性能优化技巧。我们将重点讨论如何通过合理的服务划分、高效的数据存储策略、智能的缓存机制以及有效的负载均衡技术来提升整体系统的响应速度和处理能力。
|
6天前
|
Nacos
nacos 配置页面的模糊查询
nacos 配置页面的模糊查询
|
6天前
|
安全 Java 开发者
构建高效微服务架构:后端开发的新范式Java中的多线程并发编程实践
【4月更文挑战第29天】在数字化转型的浪潮中,微服务架构已成为软件开发的一大趋势。它通过解耦复杂系统、提升可伸缩性和促进敏捷开发来满足现代企业不断变化的业务需求。本文将深入探讨微服务的核心概念、设计原则以及如何利用最新的后端技术栈构建和部署高效的微服务架构。我们将分析微服务带来的挑战,包括服务治理、数据一致性和网络延迟问题,并讨论相应的解决方案。通过实际案例分析和最佳实践的分享,旨在为后端开发者提供一套实施微服务的全面指导。 【4月更文挑战第29天】在现代软件开发中,多线程技术是提高程序性能和响应能力的重要手段。本文通过介绍Java语言的多线程机制,探讨了如何有效地实现线程同步和通信,以及如
|
6天前
|
机器学习/深度学习 Java Nacos
Nacos 配置中心(2023旧笔记)
Nacos 配置中心(2023旧笔记)
21 0
|
6天前
|
存储 前端开发 Java
第十一章 Spring Cloud Alibaba nacos配置中心
第十一章 Spring Cloud Alibaba nacos配置中心
30 0
|
1天前
|
运维 监控 负载均衡
探索微服务架构下的服务网格
【5月更文挑战第20天】 在当今日益复杂的分布式系统中,微服务架构已成为企业技术栈的重要组成部分。随着微服务数量的膨胀和网络通信的复杂化,传统的服务发现与负载均衡机制显得力不从心。本文将深入探讨服务网格这一新兴模式,它如何在微服务环境中提供更灵活、动态且高效的服务间通信解决方案。我们将剖析服务网格的核心组件、工作原理以及它如何简化分布式系统的运维难题。