一次线上剔除nacos服务的经历——bootstrap.yml与application.yml的区别
大家好,我是欧阳方超,可以扫描下方二维码关注我的公众号“欧阳方超”,后续内容将在公众号首发。

1、概述
项目中使用了nacos,但是第三方检测时扫描出一些问题(没看到具体是什么问题),修复这些问题吧还挺费劲,索性就不用nacos了吧,把配置信息全部写到yml中,随工程一起打包到jar中。
项目中使用的spring boot、spring cloud、spring cloud alibaba版本信息如下:
项目 | 版本 |
---|---|
spring-boot | 2.3.7.RELEASE |
spring-cloud | Hoxton.SR12 |
spring-cloud-alibaba | 2.2.6.RELEASE |
原本我以为只要把nacos中的配置信息写到工程代码中,就可以了呢,但是一直不行,期间遇到两个问题,一个是项目启动后一直去连本地的nacos服务,另一个是yml中的自定义配置一直找不到。 |
2、问题解决
2.1、问题一——连接本地的nacos服务
本不想连接nacos了,配置文件中连接nacos的信息也去掉了,为什么启动时还在疯狂连接本地的nacos呢,报错信息如下:
2024-10-09 16:01:12.776 ERROR 32000 --- [ main] c.a.n.c.config.http.ServerHttpAgent : [NACOS SocketTimeoutException httpGet] currentServerAddr:http://localhost:8848, err : connect timed out
2024-10-09 16:01:13.786 ERROR 32000 --- [ main] c.a.n.c.config.http.ServerHttpAgent : [NACOS SocketTimeoutException httpGet] currentServerAddr:http://localhost:8848, err : connect timed out
2024-10-09 16:01:14.796 ERROR 32000 --- [ main] c.a.n.c.config.http.ServerHttpAgent : [NACOS SocketTimeoutException httpGet] currentServerAddr:http://localhost:8848, err : connect timed out
2024-10-09 16:01:14.796 ERROR 32000 --- [ main] c.a.n.c.config.http.ServerHttpAgent : no available server
2024-10-09 16:01:14.802 ERROR 32000 --- [ main] c.a.n.client.config.impl.ClientWorker : [fixed-localhost_8848] [sub-server] get server config exception, dataId=service, group=DEFAULT_GROUP, tenant=
java.net.ConnectException: no available server
at com.alibaba.nacos.client.config.http.ServerHttpAgent.httpGet(ServerHttpAgent.java:134) ~[nacos-client-1.4.1.jar:na]
at com.alibaba.nacos.client.config.http.MetricsHttpAgent.httpGet(MetricsHttpAgent.java:51) ~[nacos-client-1.4.1.jar:na]
at com.alibaba.nacos.client.config.impl.ClientWorker.getServerConfig(ClientWorker.java:274) ~[nacos-client-1.4.1.jar:na]
原来啊,当在项目中引入 spring-cloud-starter-alibaba-nacos-config、spring-cloud-starter-alibaba-nacos-discovery依赖时,Spring Cloud Alibaba 会自动配置 Nacos 客户端。默认情况下,它会尝试连接到本地运行的 Nacos 实例(通常是在 localhost:8848),除非在配置文件中明确指定其他地址,所以把下面的依赖去掉,即可解决项目持续去连本地nacos服务的问题。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2.2、问题二——自定义配置找不到
连接本地nacos的问题解决掉之后,又遇到了新的问题,项目中使用了很多@Value注解来读取配置文件中的配置信息,但是一直就是读不到,报Could not resolve placeholder ‘xxx.xxx’ in value “${xxx.xxx}”这样的错误,原来啊,在之前使用nacos时配置文件用的是bootstrap.yml,这个问题有两个解决办法,其一是把bootstrap.yml改为application.yml,其二是添加spring-cloud-starter-bootstrap依赖。
2.2.1、bootstrap.yml改为application.yml
把bootstrap.yml改为application.yml之所以可行,是因为他俩之间存在着一些区别。
加载顺序:
bootstrap.yml:在 Spring Boot 启动时,首先加载该文件。它主要用于配置与应用程序上下文有关的设置,例如服务发现、配置服务器等。由于其优先级较高,任何在此文件中定义的属性都会在后续加载的配置文件中被覆盖。
application.yml:在 bootstrap.yml 加载之后加载。它用于定义应用程序特定的配置,如数据库连接、日志级别等。
用途:
bootstrap.yml:通常用于设置外部配置源(如 Spring Cloud Config 服务器)和其他与应用程序启动相关的配置。
application.yml:用于存储应用程序的具体配置,当不需要使用 Spring Cloud Config Server或nacos时使用。
同时使用两类配置文件
当然也会存在同时使用bootstrap.yml和application.yml的情况,在使用 Spring Cloud Config Server或nacos的场景下,通常会同时使用 bootstrap.yml 来配置客户端与 Config Server 的连接,以及 application.yml 来存放本地的默认配置或那些不希望通过 Config Server 管理的配置项。
此外,即使不使用Spring Cloud Config Server或nacos,也可以在bootstrap.yml中指定active那个配置文件,然后存放具体配置信息的文件以application-xxx.yml的方式进行命名。
2.2.2、添加spring-cloud-starter-bootstrap
spring-cloud-starter-bootstrap 是 Spring Cloud 项目中的一个重要 Starter 依赖,它的主要作用是支持 Bootstrap 配置文件的加载和管理。Bootstrap 配置文件的引入是为了更好地管理应用程序的启动配置,特别是在涉及外部配置源时(如 Spring Cloud Config Server)。
不过从 Spring Boot 2.4.x 开始,Bootstrap 配置文件(bootstrap.properties 或 bootstrap.yml)的支持需要显式引入 spring-cloud-starter-bootstrap 依赖。这一变化旨在简化配置管理,同时保持灵活性。
小插曲
我在引入spring-cloud-starter-bootstrap时遇到这样一个问题,我的项目是基于maven的多模块项目,在根pom中已经写了如下的依赖管理:
<dependencyManagement>
<dependencies>
<!-- 引入Spring Cloud依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
理论上我只要在相应的在子module的pom中,添加以下依赖即可(不需要版本号):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
但是实际更新依赖时报错了,提示spring-cloud-starter-bootstrap这个依赖缺少version,这是因为spring-cloud-starter-bootstrap是从Spring Cloud 2020.0.x才开始引入的,所以切换一下Spring Cloud版本即可,当然Spring Cloud Alibaba和Spring Boot版本也需要调整,最终我把版本调整为了如下状态:
项目 | 版本 |
---|---|
spring-boot | 2.4.9 |
spring-cloud | 2020.0.5 |
spring-cloud-alibaba | 2020.0.RC1 |
调整后,在子module中引入spring-cloud-starter-bootstrap依赖时便不再需要版本信息。 |
3、总结
一次去除线上nacos服务引发的问题,这也充分暴漏了对bootstrap.yml和application.yml的了解不足,同时也没有跟上Spring Cloud变迁时本应留意的一些问题,以后需要定期阅读 Spring Cloud 和 Spring Boot 的官方文档,了解最新版本的变化和最佳实践,以便更好地应对项目中的配置管理。
我是欧阳方超,把事情做好了自然就有兴趣了,如果你喜欢我的文章,欢迎点赞、转发、评论加关注。我们下次见。