什么是 Nacos
概览
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
简单的来说Nacos是一个动态服务发现、服务配置、服务元数据及流量管理的组件。目前已经更新到1.1.0版本
基本上Nacos = Spring Cloud Eureka + Spring Cloud Config
Nacos 可以与 Spring, Spring Boot, Spring Cloud 集成,甚至比 Spring Cloud Eureka, Spring Cloud Config更加简单和强大。
- 通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-config 实现配置的动态变更。
- 通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-discovery 实现服务的注册与发现。
动态配置服务
现在简单的入门一下Nacos的动态配置服务,Nacos可以和spring boot无缝接入。我们以一个spring boot的例子来简单说明使用方法。
1.安建Nacos环境
环境要求
- 64 bit OS,支持 Linux/Unix/Mac/Windows,推荐选用 Linux/Unix/Mac。
- 64 bit JDK 1.8+
这里我们使用linux系统,jdk使用1.8版本来安装Nacos
- 下载Nacos安装包,发布版本下载地址:https://github.com/alibaba/nacos/releases
2.上传服务器或者虚拟机
3.解压文件
4.启动nacos(启动的是单机版本),进入bin文件夹 cd nacos/bin
5.验证是否启动成功
在浏览器输入http://(你的ip):8848/nacos
默认的账号密码是nacos/nacos,如果发现访问不到先查看是否防火墙阻止访问8848端口。
2.创建spring boot项目
3.创建nacos测试项目
- 基本的注解注入配置信息
创建成功后在pom引入nacos的依赖,我们现在要使用的配置中心依赖:
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-config-spring-boot-starter</artifactId>
<version>0.2.1</version>
</dependency>
yml配置代码
server:
port: 8000
nacos:
server-addr: 192.168.253.128:8848 #自定义注解
#配置中心
config:
server-addr: 192.168.253.128:8848
#服务名称
spring:
application:
name: example-service
path: /login #自定义注解
user:
name: test #自定义注解
- 配置注册
这里我们采用更贴合spring boot的注解注入
有时候我们服务端要知道什么时候配置被修改了,什么时候配置被添加移除等操作监听,nacos也帮我们实现了这些操作。
** 采用注解注入形式@NacosInjected注入可以触发nacosConfigPublishedEvent回调,也就是配置注册到nacos的时候产生的回调,其余方式不会触发 **
先创建一个NacosConfiguration
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.spring.context.annotation.EnableNacos;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableNacos(
globalProperties =
@NacosProperties(serverAddr = "${nacos.server-addr}")
)
public class NacosConfiguration {
}
再建立一个ConfigController帮助我们实时的去注册,注销,获取配置等操作
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.alibaba.nacos.api.exception.NacosException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import static com.xiongcp.test.main.config.NacosPropertySourceConfiguration.EXAMPLE;
/**
* @author xiongcp
* @description:
* @date :2019/7/12 15:50
*/
@RestController
@RequestMapping("config")
public class ConfigController {
@NacosValue(value = "${useLocalCache:false}", autoRefreshed = true)
private boolean useLocalCache;
//采用注解注入形式@NacosInjected注入可以触发nacosConfigPublishedEvent回调,也就是配置注册到nacos的时候产生的回调,其余方式不会触发
@NacosInjected
private ConfigService configService;
@GetMapping(value = "/get")
public boolean get() {
return useLocalCache;
}
@GetMapping(value = "/register")
public boolean register() {
try {
configService.publishConfig(EXAMPLE, DEFAULT_GROUP, "useLocalCache = true");
return true;
} catch (NacosException e) {
e.printStackTrace();
return false;
}
}
@GetMapping(value = "/remove")
public boolean remove() {
try {
configService.removeConfig(EXAMPLE, DEFAULT_GROUP);
return true;
} catch (NacosException e) {
e.printStackTrace();
return false;
}
}
}
上面是对配置进行注册,注销,获取等操作
再编写监控状态变化的配置类NacosEventListenerConfiguration
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.spring.context.event.config.NacosConfigListenerRegisteredEvent;
import com.alibaba.nacos.spring.context.event.config.NacosConfigPublishedEvent;
import com.alibaba.nacos.spring.context.event.config.NacosConfigReceivedEvent;
import com.alibaba.nacos.spring.context.event.config.NacosConfigRemovedEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import static com.xiongcp.test.main.config.NacosPropertySourceConfiguration.*;
@Configuration
public class NacosEventListenerConfiguration {
private static final Logger logger = LoggerFactory.getLogger(NacosEventListenerConfiguration.class);
@NacosInjected
private ConfigService configService;
@PostConstruct
public void init() throws NacosException {
Listener listener = new AbstractListener() {
@Override
public void receiveConfigInfo(String configInfo) {
}
};
// for NacosConfigListenerRegisteredEvent(true)
//
configService.addListener(EXAMPLE, DEFAULT_GROUP, listener);
/*configService.addListener(FIRST_DATA_ID, DEFAULT_GROUP, listener);
configService.addListener(BEFORE_OS_ENV_DATA_ID, DEFAULT_GROUP, listener);
configService.addListener(AFTER_SYS_PROP_DATA_ID, DEFAULT_GROUP, listener);*/
// for NacosConfigListenerRegisteredEvent(false)
//configService.removeListener("example", DEFAULT_GROUP, listener);
}
@Bean
public ApplicationListener<NacosConfigReceivedEvent> nacosConfigReceivedEventListener() {
return new ApplicationListener<NacosConfigReceivedEvent>() {
@Override
public void onApplicationEvent(NacosConfigReceivedEvent event) {
logger.info("Listening on NacosConfigReceivedEvent - dataId : {} , groupId : {} , " + "content : {} , "
+ "source : {}", event.getDataId(), event.getGroupId(), event.getContent(), event.getSource());
}
};
}
@Bean
public ApplicationListener<NacosConfigRemovedEvent> nacosConfigRemovedEventListener() {
return new ApplicationListener<NacosConfigRemovedEvent>() {
@Override
public void onApplicationEvent(NacosConfigRemovedEvent event) {
logger.info("Listening on NacosConfigRemovedEvent - dataId : {} , groupId : {} , " + "removed : {} , "
+ "source : {}", event.getDataId(), event.getGroupId(), event.isRemoved(), event.getSource());
}
};
}
@Bean
public ApplicationListener<NacosConfigListenerRegisteredEvent> nacosConfigListenerRegisteredEventListener() {
return new ApplicationListener<NacosConfigListenerRegisteredEvent>() {
@Override
public void onApplicationEvent(NacosConfigListenerRegisteredEvent event) {
logger.info("Listening on NacosConfigListenerRegisteredEvent - dataId : {} , groupId : {} , " + "registered : {} , "
+ "source : {}", event.getDataId(), event.getGroupId(), event.isRegistered(), event.getSource());
}
};
}
@Bean
public ApplicationListener<NacosConfigPublishedEvent> nacosConfigPublishedEvent() {
return new ApplicationListener<NacosConfigPublishedEvent>() {
@Override
public void onApplicationEvent(NacosConfigPublishedEvent event) {
logger.info("Listening on NacosConfigPublishedEvent - dataId : {} , groupId : {} , " + "published : {} , "
+ "source : {}", event.getDataId(), event.getGroupId(), event.isPublished(), event.getSource());
}
};
}
}
这样我们启动项目之后可以通过nacos后台修改配置的值,通过接口来动态的配置变量的值,更方便我们进行测试。
首先启动项目,会发现这一条监听消息
进入nacos后台发现没有配置信息
这个时候我们用postman或者直接使用浏览器
返回true表示注册成功
看一下nscos控制台
已经注册成功了
再看一下程序里面的回调信息的输出
发现注册成功,也有默认值的输出
接下来修改配置的值,这里直接通过nacos的后台进行配置
点击编辑
修改值为false
点击发布
确认发布
完成之后
看项目的回调输出,发现值被修改了
我们通过写的接口查询是否修改成功,利用postman或者浏览器访问
发现值已经被修改了,操作成功。更新速度很快。
基本可以实时的更改项目里面的配置值
如果需要从nacos移除配置,也是可以实现的
postman访问remove接口
这样就能移除配置了
移除配置之后也会收到回调的信息
同时nacos控制台也会清空该配置
但是要注意的是已经配置的信息并不会更改,也就是说true修改为false不会因为移除了而更改为true
- 有时候需要将配置值做个性化的适配,nacos也是提供了first,before,after等注解配置,验证如下。
创建config包,创建NacosPropertySourceConfiguration配置类,里面的代码是从阿里demo拷贝修改了一下移植过来的。
NacosPropertySourceConfiguration.java
@Configuration
@NacosPropertySource(name = "first", dataId = FIRST_DATA_ID, first = true, autoRefreshed = true)
//dataId类似于key-values的key,用唯一的dataId可以去注册一个唯一的config信息
@NacosPropertySources({
@NacosPropertySource(name = "before-os-env", dataId = BEFORE_OS_ENV_DATA_ID, before = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME),
@NacosPropertySource(name = "after-system-properties", dataId = AFTER_SYS_PROP_DATA_ID, after = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)
})
public class NacosPropertySourceConfiguration {
private static final Logger logger = LoggerFactory.getLogger(NacosPropertySourceConfiguration.class);
public static final String FIRST_DATA_ID = "first-property-source-data-id";
public static final String BEFORE_OS_ENV_DATA_ID = "before-os-env-property-source-data-id";
public static final String AFTER_SYS_PROP_DATA_ID = "after-system-properties-property-source-data-id";
public static final String EXAMPLE = "example";
static {
String serverAddr = "192.168.253.128:8848";
try {
//创建Nacos的ConfigService
ConfigService configService = NacosFactory.createConfigService(serverAddr);
//发布到Nacos
// Publish for FIRST_DATA_ID
publishConfig(configService, FIRST_DATA_ID, "user.name = Mercy Ma");
// Publish for BEFORE_OS_ENV_DATA_ID
publishConfig(configService, BEFORE_OS_ENV_DATA_ID, "path = /home/my-path");
// Publish for AFTER_SYS_PROP_DATA_ID
publishConfig(configService, AFTER_SYS_PROP_DATA_ID, "user.name = mercyblitz");
} catch (NacosException e) {
throw new RuntimeException(e);
}
}
/**
* 注册配置
* @param configService
* @param dataId
* @param propertiesContent
* @throws NacosException
*/
private static void publishConfig(ConfigService configService, String dataId, String propertiesContent) throws NacosException {
configService.publishConfig(dataId, DEFAULT_GROUP, propertiesContent);
}
/**
* "before-os-env" overrides OS Environment variables $PATH
* @Value() 读取的yml的配置文件的值
*/
@Value("${path}")
private String path;
/**
* There are three definitions of "user.name" from
* FIRST_DATA_ID,
* SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME,
* AFTER_SYS_PROP_DATA_ID
* <p>
* Thus, "user.name = Mercy Ma" will be loaded from FIRST_DATA_ID, others will be ignored.
*/
@Value("${user.name}")
private String userName;
@PostConstruct
public void init() {
logger.info("${path} : {}", path); // -> "home/my-path"
logger.info("${user.name} : {}", userName); // -> "Mercy Ma"
logger.info("Java System ${user.name} : {}", System.getProperty("user.name"));
logger.info("OS Env ${PATH} : {}", System.getenv("PATH"));
}
}
启动spring boot项目,我们查看log文件
我们可以发现init方法里面读取到的path被覆盖了,并不是yml文件里面的值,配置被修改了。这个也就是注解里面before = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME的作用
user.name输出的是Mercy Ma而不是mercyblitz是因为dataId为FIRST_DATA_ID的位置里面配置了first = true,那么就只会加载第一次的配置,忽略后面的配置。
autoRefreshed = true 表示自动刷新配置,在nacos后台修改配置后会自动更新,默认是false
我们可以查看下nacos的后台配置文件数据
可以发现我们注册进去的几个配置信息,在里面可以进行查看修改等操作。
总结:nacos配置中心友好方便,功能齐全,后续会对nacos的其他功能进行说明。
项目github地址:https://github.com/xiongcp/NacosTest