SpringBoot 使用 Nacos 作为配置中心


官方文档地址

1. 下载安装

在官方文档的快速开始目录下的Nacos文档中,就主要介绍了这部分内容。我们可以直接在2.下载源码或者安装包找到最新稳定版本下载,如下图所示:
在这里插入图片描述
点开最新稳定版本后,会看到很一个 Releases 列表,找到最新的非 BEAT 版本,目前最新稳定版本是 1.2.1,直接点击下载 zip 包,解压完就能使用。(类似于 Tomcat 的压缩包,Linux 版本和 Windows 版本都在一个压缩包中。)
在这里插入图片描述
这个下载速度很慢,这里提供一个百度网盘链接:

链接:https://pan.baidu.com/s/1BtAsrMGL3Hid3Rio4yo37Q 
提取码:yubc

我这里是 Windows 系统,解压安装到了 D 盘(这里需要注意的是安装路径中的目录不要有空格,否则会启动失败,黑窗口一闪而逝。),在D:\nacos\bin下双击 startup.cmd 运行文件或者在命令行窗口执行启动命令:

cmd startup.cmd

服务启动成功如下图所示:
在这里插入图片描述
接下来就可以直接通过下面地址来访问控制台了:

http://127.0.0.1:8848/nacos

默认账号密码都是 nacos。

2. 界面操作

我本地的项目名为 demo,所以直接新建了一个命名空间 demo,在 demo 下添加配置,其实就是把项目中的配置文件的内容复制粘贴 nacos 中,主要需要注意下 dataId 和 Group 的命名。添加完成后如下图所示:
在这里插入图片描述
在这里插入图片描述

3. 项目集成

本文主要介绍 SpringBoot 项目使用 Nacos 作配置中心,在官方文档的快速开始目录下的Nacos Spring Boot文档中有简单介绍。

3.1. 添加依赖

<dependency>
	<groupId>com.alibaba.boot</groupId>
	<artifactId>nacos-config-spring-boot-starter</artifactId>
	<version>0.2.7</version>
</dependency>

文档中提示:版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本。我的 SpringBoot 版本为 2.1.7.RELEASE,这里我选择引入目前最新的 0.2.7 版本。

3.2. 项目配置

关于 Nacos Spring Boot 的详细文档请参看:nacos-spring-boot-project。这里可以看到各版本的一些新增内容。下面列出官方给出的一些配置,可以参考以下配置参数进行设置:

# 开启配置预加载功能
nacos.config.bootstrap.enable=true
# 主配置 服务器地址
nacos.config.server-addr=192.168.16.104:8848
# 主配置 data-id
nacos.config.data-id=people
# 主配置 group-id
nacos.config.group=DEFAULT_GROUP
# 主配置 配置文件类型
nacos.config.type=properties
# 主配置 最大重试次数
nacos.config.max-retry=10
# 主配置 开启自动刷新
nacos.config.auto-refresh=true
# 主配置 重试时间
nacos.config.config-retry-time=2333
# 主配置 配置监听长轮询超时时间
nacos.config.config-long-poll-timeout=46000
# 主配置 开启注册监听器预加载配置服务(除非特殊业务需求,否则不推荐打开该参数)
nacos.config.enable-remote-sync-config=true

# 支持日志级别的加载时机
nacos.config.bootstrap.log-enable=true
# 支持配置 data-ids 的设置方式
nacos.config.data-ids=people,test
# 支持 nacos 1.2.0 新增的权限控制功能
nacos.config.username=nacos
nacos.config.password=nacos
# 允许nacos上的配置优先于本地配置
nacos.config.remote-first=true

ext-config[index] 的优先级,index 越小,优先级越高,从 0 开始。

nacos.config.ext-config[0].data-id=test
nacos.config.ext-config[0].group=DEFAULT_GROUP
nacos.config.ext-config[0].max-retry=10
nacos.config.ext-config[0].type=yaml
nacos.config.ext-config[0].auto-refresh=true
nacos.config.ext-config[0].config-retry-time=2333
nacos.config.ext-config[0].config-long-poll-timeout=46000
nacos.config.ext-config[0].enable-remote-sync-config=true

接下来说下我的配置。将 application-dev.yml 文件内容修改为:

nacos:
  config:
    bootstrap:
      enable: true
      log-enable: true
    context-path: /nacos
    namespace: demo
    group: demo
    data-id: application-dev.yml
    type: yaml
    auto-refresh: true
    remote-first: true
    server-addr: 127.0.0.1:8848
    username: nacos
    password: nacos

将 application-prod.yml 文件内容修改为:

nacos:
  config:
    bootstrap:
      enable: true
      log-enable: true
    context-path: /nacos
    namespace: demo
    group: demo
    data-id: application-prod.yml
    type: yaml
    auto-refresh: true
    remote-first: true
    server-addr: 127.0.0.1:8848
    username: nacos
    password: nacos

到这里基本已经实现远端配置了,不过没有实现远程刷新配置,实时生效。

3.3. 实时刷新

比如我在 nacos 上 demo 命名空间下的 application-dev.yml 中添加了一条自定义配置:

custom:
  str: 这是测试环境

在我的 demo 程序中分别使用 Spring 提供的 @Value 注解 和 Nacos 提供的 @NacosValue 注解去获取该属性值:

@Value("${custom.str}")
private String string1;

@NacosValue(value = "${custom.str}", autoRefreshed = true)
private String string2;

以 dev 环境启动项目,都可以获取到值这是测试环境,但是在我手动修改 nacos 中的配置为以下内容时:

custom:
  str: 这是测试环境(已修改)

此时不重启项目,则 string1 的值依然为这是测试环境,而 string2 的值已经自动刷新为这是测试环境(已修改)

4. 问题记录

4.1. Failed to rename context

这个错误在本地的 demo 项目和生产项目中都出现了。SpringBoot 项目启动的时候会报该错误,错误内容如下:

[Nacos Config Boot] : The preload log configuration is enabled
2020-07-08 18:31:29 [ERROR] [org.springframework.boot.SpringApplication:822] - Application run failed
java.lang.IllegalStateException: Logback configuration error detected: 
ERROR in ch.qos.logback.classic.joran.action.ContextNameAction - Failed to rename context [nacos] as [demo] java.lang.IllegalStateException: Context has been already given a name

这个其实是日志上下文重命名错误。我的 logback-spring.xml 里面配置了日志上下文名字:

<contextName>demo</contextName>

而在 nacos 配置中开启了支持日志级别的加载时机

nacos.config.bootstrap.log-enable=true

所以报错了,这两个保留一个即可,我是直接把 contextName 标签删掉了。

4.2. get changed dataId error

这个错误只在生产项目中出现了。SpringBoot 项目启动的时候会报该错误,错误内容如下:

c.a.n.client.config.impl.ClientWorker    : [fixed-nacos.nbiz-k8s.tryudesk.com-kun] [check-update] get changed dataId error, code: 403

这个错误是由于引入的 starter 包中的 fastjson 包被排除掉了,重新添加上 fastjson 包,错误就解决了。

<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>nacos-config-spring-boot-starter</artifactId>
    <version>0.2.7</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.70</version>
</dependency>

一般大家是不会遇到这个错误的,因为 starter 包内部集成了 fastjson。
在这里插入图片描述
这里聊一下我出现这个问题的原因:pom.xml 中的 maven 做了父级约束,我们这个项目是 abc-web-api,在 pom.xml 依赖了 abc-common。

<dependencies>
	<dependency>
	    <groupId>cn.udesk.cck</groupId>
	    <artifactId>abc-common</artifactId>
	    <version>0.0.1-SNAPSHOT</version>
	</dependency>
</dependencies>

abc-common 的 pom.xml 父级为 abc-parent。

<parent>
	<groupId>cn.udesk.cck</groupId>
	<artifactId>abc-parent</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<relativePath>../abc-parent</relativePath>
</parent>

abc-parent 的 pom.xml 父级为 common-parent。

<parent>
    <groupId>cn.udesk.framework</groupId>
    <artifactId>common-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <relativePath></relativePath>
</parent>

而 common-parent 的 pom.xml 中定义了一个约束。意思就是只要你引入了 nacos 这个 starter 包,就会自动排除 fastjson 包。而我是在 abc-common 中引入的,自然被排除了。

<properties>
	<fastjson.version>1.2.70</fastjson.version>
	<nacos-config-spring-boot-starter.version>0.2.7</nacos-config-spring-boot-starter.version>
</properties>
<dependencyManagement>
	<dependencies>
		<dependency>
		    <groupId>com.alibaba.boot</groupId>
		    <artifactId>nacos-config-spring-boot-starter</artifactId>
		    <version>${nacos-config-spring-boot-starter.version}</version>
		    <exclusions>
		        <exclusion>
		            <groupId>com.alibaba</groupId>
		            <artifactId>fastjson</artifactId>
		        </exclusion>
		    </exclusions>
		</dependency>
		<dependency>
		    <groupId>com.alibaba</groupId>
		    <artifactId>fastjson</artifactId>
		    <version>${fastjson.version}</version>
		</dependency>
	</dependencies>
</dependencyManagement>

注意:该错误用同样方法在我的 demo 项目中没有重现,所以以上并不是根本原因。

4.3. Could not resolve placeholder

错误日志如下所示:

2020-07-08 19:36:40.360  WARN 3928 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'awsS3StorageConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'cloud.aws.region.static' in value "${cloud.aws.region.static}"
2020-07-08 19:36:42.879  INFO 3928 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-3} closing ...
2020-07-08 19:36:42.892  INFO 3928 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-3} closed
2020-07-08 19:36:42.894  INFO 3928 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-4} closing ...
2020-07-08 19:36:42.896  INFO 3928 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-4} closed
2020-07-08 19:36:42.910  INFO 3928 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} closing ...
2020-07-08 19:36:42.913  INFO 3928 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} closed
2020-07-08 19:36:42.914  INFO 3928 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-2} closing ...
2020-07-08 19:36:42.917  INFO 3928 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-2} closed
2020-07-08 19:36:42.918  INFO 3928 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-0} closing ...
2020-07-08 19:36:42.920  INFO 3928 --- [           main] .c.NacosValueAnnotationBeanPostProcessor : class com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor was destroying!
2020-07-08 19:36:42.920  INFO 3928 --- [           main] AnnotationNacosInjectedBeanPostProcessor : class com.alibaba.nacos.spring.beans.factory.annotation.AnnotationNacosInjectedBeanPostProcessor was destroying!
2020-07-08 19:36:42.924  INFO 3928 --- [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2020-07-08 19:36:42.951 ERROR 3928 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'awsS3StorageConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'cloud.aws.region.static' in value "${cloud.aws.region.static}"
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:382)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:608)
	at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1234)
	at com.alibaba.nacos.spring.context.event.AnnotationListenerMethodProcessor.processBeans(AnnotationListenerMethodProcessor.java:98)
	at com.alibaba.nacos.spring.context.event.AnnotationListenerMethodProcessor.onApplicationEvent(AnnotationListenerMethodProcessor.java:93)
	at com.alibaba.nacos.spring.context.event.AnnotationListenerMethodProcessor.onApplicationEvent(AnnotationListenerMethodProcessor.java:55)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359)
	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1204)
	at cn.udesk.kun.Application.main(Application.java:17)
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'cloud.aws.region.static' in value "${cloud.aws.region.static}"
	at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:178)
	at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:124)
	at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:237)
	at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:211)
	at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:175)
	at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:851)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1196)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1175)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:595)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:376)
	... 27 common frames omitted

解决方法是在启动类中加入以下代码:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
    	// 新加代码
        System.setProperty("ignoreUnresolvablePlaceholders", "true");
        SpringApplication.run(Application.class, args);
    }
}

以前在 Spring 项目中通过配置多个PropertyPlaceholderConfigurer来分别引入多个 properties 文件,此时需要在每个PropertyPlaceholderConfigurer中添加

<property name="ignoreUnresolvablePlaceholders" value="true" />

ignoreUnresolvablePlaceholders为是否忽略不可解析的Placeholder,如配置了多个,则需设置为true。

可以参考下这篇文章:spring项目启动报"Could not resolve placeholder"解决

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值