文章目录
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"解决。