前置条件:jdk、SpringBoot项目、Nacos、Linux服务器(可无)

具体版本:jdk11、SpringBoot 2.3.5.RELEASE、Nacos 2.0.3、Centos 6

目标:SpirngBoot项目使用Nacos作为配置中心动态管理项目配置

相关问题及解答参考本文末尾

原文首发:chenetchen.ltd,个人博客网站。

前言

使用SringBoot框架开发的项目,虽然免去了在Tomcat上的配置,可以将项目打成jar包后在服务器上发布,但是如果需要修改配置文件,需要停下项目,使用vim打开jar包修改配置文件,然后重启项目。

过程不免繁杂,而且需要启停项目,需要专业人员在服务器上操作。在之前的工作中,学习到的JMX,可以动态获取或修改参数,但是JMX的主要作用是用于监控,而不是作为一个配置,且调用JMX连接也麻烦,学习成本较大,使用JMX查看并管理参数需要使用到jconsole工具,也存在学习成本,一样需要专业人员来操作。

于是乎,回想起之前学习的分布式组件中,Nacos进入了我的选择范围

Nacos

Nacos是阿里旗下的一款开源软件,支持服务注册与发现、配置管理以及微服务管理的组件。Nacos的目标是为了取代过去常用的注册中心(Zookeeper、Eureka等),以及配置中心(Spring Cloud Config等)。Nacos集成了注册中心和配置中心的功能。

基于此,虽然是SpirngBoot项目,服务注册与发现用不上,但是可以使用Nacos配置中心的功能,对项目的配置文件进行动态管理。

SpringBoot使用Nacos

Maven配置

根据官方文档——Nacos Spring Boot 快速开始,在Spirng Boot项目的Maven中引入nacos-config-spring-boot-starter依赖

<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-config-spring-boot-starter</artifactId>
<version>${latest.version}</version>
</dependency>

需要注意的是,网上对于Spring Boot项目使用的Nacos依赖是哪一个,存在错误的版本,相当一部分的帖子和博客,提到的是spring-cloud-starter-alibaba-nacos-discovery和spring-cloud-starter-alibaba-nacos-config,虽然这两个也能在Spring Boot中使用,但是配置更加繁琐。可以参考SpringBoot整合nacos实现配置中心(配置动态更新)

Nacos配置

启动Nacos

对于本文中的环境,即单个Spirng Boot非分布式集群的项目而言,Nacos需要以单机的形式启动。

在Windows下修改/nacos/bin目录下的startup.cmd脚本文件,将其中的 set MODE="cluster"修改为 set MODE="standalone",即可实现Nacos的单机启动。

配置管理

Nacos启动成功后(本文默认在测试情况下都在Windows环境下单机启动Nacos,保持默认配置),访问 localhost:8848/nacos,使用naocs/nacos登录Nacos平台。

在左侧的配置管理中点击配置列表,再点击右侧页面主体列表上方的加号按钮,添加配置,Data Id为 test,分组默认,格式选择properties,配置内容为

useLocalCache=true

发布成功后,返回。

项目配置

Nacos配置

项目配置有两种方法,一种是使用注解,在SpringBoot项目的主启动类上使用

@NacosPropertySource(dataId = "test", autoRefreshed = true)

dataId:Nacos中配置的配置ID
autoRefreshed:开启自动刷新

另一种方式是使用配置文件,因为前文中提到了Spring Boot中使用的是nacos-config-spring-boot-starter,而非Cloud中难道依赖,所以此处是无法使用bootstrap配置文件的(如要使用bootstrap配置,需要引入cloud相关的配置文件),直接在application配置文件中配置好nacos相关的配置。

nacos:
config:
type: yaml
server-addr: 127.0.0.1:8848
context-path: nacos
data-id: test
auto-refresh: true
bootstrap:
enable: true

需要注意的是,在以上配置中,有个别配置需要注意,关于此问题,参看SpringBoot2集成nacos(一)

测试代码

参看Nacos官方提供的demo,编写如下测试类(SpringBoot项目需要引入web依赖)

@Controller
public class Test {
@NacosValue(value = "${useLocalCache:false}", autoRefreshed = true)
private boolean useLocalCache; @RequestMapping(value = "/get", method = RequestMethod.GET)
@ResponseBody
public boolean get() {
return useLocalCache;
}
}

启动项目(如果配置文件中——Nacos配置和项目配置中均未指定项目端口,且80端口被占用,需要注意添加额为项目端口配置,server.prot=xxx,配置在Nacos或application配置文件中均可)

访问/get测试,返回为true即表示SpringBoot项目正确获取Nacos中的配置。

版本问题

如果上方的基本流程一切顺利,那么恭喜你没有遇到版本问题;如果Nacos启动失败、项目启动失败、获取不到值等,那么接下来的部分应该可以解决你的问题。

SpirngBoot和Nacos Spring Boot

首先是SpringBoot的版本和Nacos的pom文件版本,此问题一般出现在项目启动失败,这是因为SpringBoot的版本和nacos-config-spring-boot-starter的版本问题。一般会出现如下错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'nacosConfigurationPropertiesBinder': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.alibaba.boot.nacos.config.binder.NacosBootConfigurationPropertiesBinder]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/boot/context/properties/ConfigurationBeanFactoryMetadata
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:315) ~[spring-beans-5.3.2.jar:5.3.2]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:296) ~[spring-beans-5.3.2.jar:5.3.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1356) ~[spring-beans-5.3.2.jar:5.3.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1206) ~[spring-beans-5.3.2.jar:5.3.2]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.alibaba.boot.nacos.config.binder.NacosBootConfigurationPropertiesBinder]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/boot/context/properties/ConfigurationBeanFactoryMetadata
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:225) ~[spring-beans-5.3.2.jar:5.3.2]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117) ~[spring-beans-5.3.2.jar:5.3.2]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:311) ~[spring-beans-5.3.2.jar:5.3.2]
... 20 common frames omitted
Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/context/properties/ConfigurationBeanFactoryMetadata
at com.alibaba.boot.nacos.config.binder.NacosBootConfigurationPropertiesBinder.<init>(NacosBootConfigurationPropertiesBinder.java:51) ~[nacos-config-spring-boot-autoconfigure-0.2.7.jar:0.2.7]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_181]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_181]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_181]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_181]
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:212) ~[spring-beans-5.3.2.jar:5.3.2]
... 22 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_181]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_181]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) ~[na:1.8.0_181]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_181]
... 28 common frames omitted

错误提示创建名为'nacosConfigurationPropertiesBinder'的bean失败。这是因为nacos-config-spring-boot-starter支持的SpringBoot版本比项目当前使用的版本低,而SpringBoot在2.4之后删掉了ConfigurationBeanFactoryMetadata,需要将SpringBoot的版本降级到2.3.x。

Nacos Spring Boot和JDK

是的,没错,JDK此处也插了一脚,是可能存在JDK的版本问题的。

在JDK11的的情况下,nacos-config-spring-boot-starter版本过低,项目启动不过抛出异常,但是访问测试代码时,无法获取Nacos配置中心中配置的值。

经由网友@yvioo测试,在JDK11下,使用nacos-config-spring-boot-starter版本为0.2.7及以上,可以成功获取Nacos配置中心的值(我测试的时候依旧为未成功获取),建议使用0.2.10版本。

部署项目到Linux上

经过上方的一系列测试,SpringBoot项目已经能完整的获取Nacos配置中心中值,现在,需要将环境部署到Linux服务器上使用。

Linux安装Nacos

相信网上关于在Linux上部署Nacos的教程数不胜数了,但是大部分的教程在我眼里还是不够细致,并没有提到各种各样的bug,在经由我八哥小王子的测试下,果不其然触发了各式各样的bug,为此,下文中不过多描述如何安装nacos,而是如何解决bug。

简单概述一下Linux安装Nacos,从官方下载nacos.tar.gz安装包后,解压到/usr/local目录下,便安装成功了,一切顺利的话,像Windows下修改启动模式,从集群修改为单机后,直接 ./startup.sh -m standalone即可启动Nacos了。

Java环境问题

Nacos启动失败,首先排查一下Java环境,Nacos实际上为jar包,需要使用Java来启动。

如果熟悉shell脚本,可以看到在nacos/bin目录下的startup.sh脚本中,是有获取Java环境的。

[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$JAVA_HOME/java/jdk-11.0.11
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/opt/taobao/java
[ ! -e "$JAVA_HOME/bin/java" ] && unset JAVA_HOME

首先可以先使用命令 echo $JAVA_HOME 查看在/etc/profile中定义的JAVA_HOME路径,对比Nacos启动脚本中获取的JAVA_HOME路径。

JDK11问题

是的,没错,JDK11的问题又来了,在JDK11的环境下启动Nacos也可能失败,参考Linux下使用JDK11部署Nacos启动报错:Could not find or load main class,需要将启动脚本startup.sh中的如下配置进行替换

JAVA_OPT_EXT_FIX="-Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${JAVA_HOME}/lib/ext"
替换为
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${JAVA_HOME}/lib/ext" echo "$JAVA $JAVA_OPT_EXT_FIX ${JAVA_OPT}"
替换为
echo "$JAVA ${JAVA_OPT}" echo "$JAVA $JAVA_OPT_EXT_FIX ${JAVA_OPT}" > ${BASE_DIR}/logs/start.out 2>&1 &
nohup "$JAVA" "$JAVA_OPT_EXT_FIX" ${JAVA_OPT} nacos.nacos >> ${BASE_DIR}/logs/start.out 2>&1 &
替换为
echo "$JAVA ${JAVA_OPT}" > ${BASE_DIR}/logs/start.out 2>&1 &
nohup $JAVA ${JAVA_OPT} nacos.nacos >> ${BASE_DIR}/logs/start.out 2>&1 &

即可成功启动。

JVM内存问题

替换完后,进行启动,此时应该已经可以成功启动了,ps -ef|grep nacos命令也能成功看到nacos的pid,但是当你访问服务器的nacos地址时,发现无法请求(默认排除了端口占用,防火墙未开放端口等问题),且重新使用ps命令查看,会发现nacos自动停止了。

这是因为nacos2.0版本,在配置文件中默认指定了jvm的大小。同样是在Nacos的启动脚本startup.sh文件中。

#===========================================================================================
# JVM Configuration
#===========================================================================================
if [[ "${MODE}" == "standalone" ]]; then
JAVA_OPT="${JAVA_OPT} -Xms512m -Xmx512m -Xmn256m"
JAVA_OPT="${JAVA_OPT} -Dnacos.standalone=true"
else
if [[ "${EMBEDDED_STORAGE}" == "embedded" ]]; then
JAVA_OPT="${JAVA_OPT} -DembeddedStorage=true"
fi
JAVA_OPT="${JAVA_OPT} -server -Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs/java_heapdump.hprof"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages" fi if [[ "${FUNCTION_MODE}" == "config" ]]; then
JAVA_OPT="${JAVA_OPT} -Dnacos.functionMode=config"
elif [[ "${FUNCTION_MODE}" == "naming" ]]; then
JAVA_OPT="${JAVA_OPT} -Dnacos.functionMode=naming"
fi

其中的JAVA_OPT="${JAVA_OPT} -Xms512m -Xmx512m -Xmn256m"一行指定了JVM的初始容量和最大容量。

-Xms: 设定程序启动时占用内存大小
-Xmx: 设定程序运行期间最大可占用的内存大小
-Xmn:新生代大小

针对Linux系统容量手动修改即可成功启动。

JAVA_OPT="${JAVA_OPT} -Xms100m -Xmx256m -Xmn200m"

至此,SpirngBoot项目使用Nacos作为配置中心,动态管理配置完成。

参考资料

  1. Nacos Spring Boot 快速开始

  2. SpringBoot2集成nacos(一)

  3. nacos-spring-boot-config-example

  4. spring boot使用nacos作为配置中心实践

  5. SpringBoot bootstrap 配置文件没有生效

  6. Linux下使用JDK11部署Nacos启动报错:Could not find or load main class

  7. centos或者linux的云服务器总是启动不了nacos的问题解决

SpringBoot项目使用Nacos作为配置中心的更多相关文章

  1. Nacos(四):SpringCloud项目中接入Nacos作为配置中心

    前言 通过前两篇文章: Nacos(二):Nacos与OpenFeign的对接使用 Nacos(三):SpringCloud项目中接入Nacos作为注册中心 相信大家已经对Nacos作为注册中心的基本 ...

  2. Nacos系列:基于Nacos的配置中心

    前言 在看正文之前,我想请你回顾一下自己待过的公司都是怎么管理配置的,我想应该会有以下几种方式: 1.硬编码 没有什么配置不配置的,直接写在代码里面,比如使用常量类 优势:对开发友好,开发清楚地知道代 ...

  3. java架构之路-(微服务专题)feign的基本使用和nacos的配置中心

    上次回归: 上次我们说了ribbon的基本使用,包括里面的内部算法,算法的细粒度配置,还有我们自己如何实现我们自己的算法,主要还是一些基本使用的知识,还不会使用ribbon的小伙伴可以回去看一下上一篇 ...

  4. nacos作为配置中心动态刷新@RefreshScope添加后取值为null的一个问题

    之前springboot项目常量类如下形式: @Component @RefreshScope//nacos配置中心时添加上 public class Constants { @Value(" ...

  5. 程序员你是如何使用Nacos作为配置中心的?

    假如你使用的是spring-cloud-alibaba微服务技术栈 单个服务独有配置文件 即去除应用程序的状态,配置统一外部化管理,方便进行水平的伸缩. 集成步骤: 假如我有一个应用app-desig ...

  6. 使用nacos作为配置中心统一管理配置

    基础环境 引入所需依赖包 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>s ...

  7. ******可用 SpringBoot 项目打包分开lib,配置和资源文件

    spring-boot多模块打包后,无法找到其他模块中的类https://blog.csdn.net/Can96/article/details/96172172 关于SpringBoot项目打包没有 ...

  8. Nacos作为配置中心时,多个服务共用一个dataId的配置

    写在前面 本文是对我之前一篇文章<Spring Cloud+nacos+Feign,实现注册中心及配置中心>的补充.此文章中简单写了如何将Nacos作为配置中心.在使用配置中心时,我们会遇 ...

  9. SpringCloud项目中使用Nacos作为配置中心

    参考:https://blog.csdn.net/qq_33619378/article/details/96991237 Nacos-server启动 这里就不说了 新建配置 在Nacos-Serv ...

随机推荐

  1. SpringCloud微服务实战——搭建企业级开发框架(二十六):自定义扩展OAuth2实现短信验证码登录

    现在手机验证码登录似乎是每个网站必备的功能,OAuth2支持扩展自定义授权模式,前面介绍了如何在系统集成短信通知服务,这里我们进行OAuth2的授权模式自定义扩展,使系统支持短信验证码登录. 1.在g ...

  2. Atcoder 2444 - JOIOI 王国(二分)

    题面传送门 记 \(mxi\) 为 IOI 国海拔的最大值,\(mni\) 为 IOI 国海拔的最小值,\(mxj\) 为 JOI 国海拔的最大值,\(mnj\) 为 JOI 国海拔的最小值. 不难发 ...

  3. 省时省心DTM,广告转化无难题

    内容来源:华为开发者大会2021 HMS Core 6 App Services技术论坛,主题演讲<华为分析服务,助您打造数智化运营闭环方案>. 演讲嘉宾:华为消费者云服务 分析产品总监 ...

  4. POLLOUT/POLLINT事件触发测试

    一般poll使用过程中都是检测POLLIN事件,表示描述符有事件可以处理了,需要我们处理.对POLLOUT事件触发的方式相对较少,网上也有很多对此触发的疑问,利用实际项目中用的一个用法,下面做了个测试 ...

  5. A Child's History of England.29

    You have not forgotten the New Forest which the Conqueror made, and which the miserable people whose ...

  6. act.四级

    act的词源是do, 干着或干了的事情也可以叫act.action: doing sth; act: n. action, v. do; activity: busy, energetic, or占据 ...

  7. Spark集群环境搭建——服务器环境初始化

    Spark也是属于Hadoop生态圈的一部分,需要用到Hadoop框架里的HDFS存储和YARN调度,可以用Spark来替换MR做分布式计算引擎. 接下来,讲解一下spark集群环境的搭建部署. 一. ...

  8. Javascript 数组对象常用的API

    常用的JS数组对象API ES5及以前的Api ECMAScript5为数组定义了5个迭代方法,每个方法接收两个参数, 一个是每项运行的函数,一个是运行该函数的作用域对象(可选项),传入这些方法的函数 ...

  9. Spring Boot Actuator:健康检查、审计、统计和监控

    Spring Boot Actuator可以帮助你监控和管理Spring Boot应用,比如健康检查.审计.统计和HTTP追踪等.所有的这些特性可以通过JMX或者HTTP endpoints来获得. ...

  10. spring下春注解的声明式事务控制

    package com.hope.test;import com.hope.domain.Account;import com.hope.service.IAccountService;import ...