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

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 本文是采用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相关的配置类么。

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

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

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

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

目录
相关文章
|
2月前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
160 57
|
11天前
|
JSON Java Apache
Java基础-常用API-Object类
继承是面向对象编程的重要特性,允许从已有类派生新类。Java采用单继承机制,默认所有类继承自Object类。Object类提供了多个常用方法,如`clone()`用于复制对象,`equals()`判断对象是否相等,`hashCode()`计算哈希码,`toString()`返回对象的字符串表示,`wait()`、`notify()`和`notifyAll()`用于线程同步,`finalize()`在对象被垃圾回收时调用。掌握这些方法有助于更好地理解和使用Java中的对象行为。
|
2月前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
65 8
|
2月前
|
Java 网络安全 Nacos
Nacos作为流行的微服务注册与配置中心,其稳定性与易用性广受好评
Nacos作为流行的微服务注册与配置中心,其稳定性与易用性广受好评。然而,“客户端不发送心跳检测”是使用中常见的问题之一。本文详细探讨了该问题的原因及解决方法,包括检查客户端配置、网络连接、日志、版本兼容性、心跳检测策略、服务实例注册状态、重启应用及环境变量等步骤,旨在帮助开发者快速定位并解决问题,确保服务正常运行。
51 5
|
2月前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
2月前
|
数据采集 Java API
java怎么设置代理ip:简单步骤,实现高效网络请求
本文介绍了在Java中设置代理IP的方法,包括使用系统属性设置HTTP和HTTPS代理、在URL连接中设置代理、设置身份验证代理,以及使用第三方库如Apache HttpClient进行更复杂的代理配置。这些方法有助于提高网络请求的安全性和灵活性。
|
2月前
|
Java Android开发
Eclipse 创建 Java 类
Eclipse 创建 Java 类
31 0
|
Java 容器 Spring
SpringBoot配置类注解
在使用springBoot进行开发时,经常会碰到把配置文件的属性值注入到某个JAVA类的属性中,可以使用@value注解注入配置文件的单个属性,也可以使用@ConfigurationProperties注入对象的多个属性。
739 0
|
3月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
199 1
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
131 62