Nacos的简单使用
1、简述
nacos官方文档:https://nacos.io/docs/latest/guide/user/sdk/
nacos下载:https://github.com/alibaba/nacos?tab=readme-ov-file
nacos是一个SpringBoot项目,下载后直接可以使用
nacos以单节点启动:
D:\nacos-server-2.0.3\nacos\bin>startup.cmd -m standalone
启动后访问地址:localhost:8848/nacos
默认用户名密码都是nacos
2、配置管理
2.1 新建配置
在nacos新建完配置后,作为一个SpringBoot应用,如何获取配置?
2.2 Java SDK获取配置和监听配置
除了获取配置getConfig
和监听配置addListener
,还有很多其他的Api;
官网:https://nacos.io/Zh-cn/docs/sdk.html
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.2.1</version>
</dependency>
<dependencies>
ConfigManagement_JavaSDK
package com.lmcode;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.Executor;
public class ConfigManagement_JavaSDK {
public static void main(String[] args) {
try{
String serverAddr = "localhost:8848"; //nacos的地址
String dataId = "test"; //想要获取的配置文件的名字
String group = "DEFAULT_GROUP"; //分组
Properties properties = new Properties();
properties.put("serverAddr",serverAddr);
ConfigService configService = NacosFactory.createConfigService(properties);
// 获取nacos配置
String content = configService.getConfig(dataId,group,5000);
System.out.println(content);
// 监听nacos配置
configService.addListener(dataId, group, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
System.out.println(configInfo);
}
});
// 让当前线程不要停掉
System.in.read();
}catch (NacosException nacosException){
nacosException.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果展示
此时在Nacos控制台修改配置控制台会同步打印修改后的配置
ConfigService源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.alibaba.nacos.api.config;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
public interface ConfigService {
String getConfig(String var1, String var2, long var3) throws NacosException;
String getConfigAndSignListener(String var1, String var2, long var3, Listener var5) throws NacosException;
void addListener(String var1, String var2, Listener var3) throws NacosException;
boolean publishConfig(String var1, String var2, String var3) throws NacosException;
boolean publishConfig(String var1, String var2, String var3, String var4) throws NacosException;
boolean publishConfigCas(String var1, String var2, String var3, String var4) throws NacosException;
boolean publishConfigCas(String var1, String var2, String var3, String var4, String var5) throws NacosException;
boolean removeConfig(String var1, String var2) throws NacosException;
void removeListener(String var1, String var2, Listener var3);
String getServerStatus();
void shutDown() throws NacosException;
}
2.3 Spring拉取配置与自动刷新
pom.xml
nacos-spring-context
除了基础的nacos-client
,还提供了一些注解功能
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
<version>1.1.1</version>
</dependency>
ConfigManagement_SpringConfig
提供Spring配置,包扫描
自动刷新:配置发生改变会自动生效
package com.lmcode;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan("com.lmcode")
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848"))
@NacosPropertySource(dataId = "test", autoRefreshed = true)
public class ConfigManagement_SpringConfig {
}
ConfigManagement_Spring
创建一个容器
package com.lmcode;
import com.lmcode.service.UserService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ConfigManagement_Spring {
public static void main(String[] args) {
//创建容器
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(ConfigManagement_SpringConfig.class);
UserService userService = annotationConfigApplicationContext.getBean(UserService.class);
userService.test();
}
}
UserService
使用@Value或@NacosValue使用某一个具体的配置项
@EnableNacosConfig
会负责把指定的dataId
的配置项拉取到应用,并封装为PropertySource
对象添加到Environment
对象中
package com.lmcode.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class UserService {
@Value("${spring.datasource.username}")
private String username;
public void test(){
System.out.println(username);
}
}
结果展示
报错修改:https://www.cnblogs.com/lm02/p/18149849
2.4 SpringBoot拉取配置与自动刷新
pom.xml
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-config-spring-boot-starter</artifactId>
<version>0.2.12</version>
</dependency>
application.properties
配置不一定要在配置文件写,也可以在启动时配置,另外,这里的配置一般不用改变,但是nacos里的配置可能常发生改变,nacos的配置改变后不用重启服务。nacos的配置也可以复用
nacos.config.server-addr=127.0.0.1:8848
Application
package com.lmcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
UserController
package com.lmcode.controller;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@NacosValue(value = "${spring.datasource.username}",autoRefreshed = true)
private String username;
@GetMapping("/getusername")
public String getUsername(){
return username;
}
}
页面输出
此时修改配置会自动刷新【必须使用@NacosValue(value = "${spring.datasource.username}",autoRefreshed = true)
,不能使用@Value
】
配置方式2:取消启动类注解
@NacosPropertySource
使用配置文件
application.properties
server.port=9022
nacos.config.server-addr=127.0.0.1:8848
nacos.config.data-id=test
nacos.config.auto-refresh=true
nacos.config.bootstrap.enable=true
2.5 SpringCloud拉取配置与自动刷新===
自动刷新原理:https://www.cnblogs.com/lm02/p/18147099
pom.xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
bootstrap.properties
有的SpringCloud的版本会首先读取bootstrap的配置
spring.application.name=test
spring.cloud.nacos.server-addr=127.0.0.1:8848
server.port=9033
版本兼容
Nacos官方文档:https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
UserController
package lmcode.controller;
import lmcode.config.CommonConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class UserController {
@Autowired
private CommonConfig commonConfig;
@GetMapping("/getusername")
public String getUsername(){
return commonConfig.getUsername();
}
}
CommonConfig
package lmcode.config;
import com.alibaba.nacos.api.config.annotation.NacosValue;
//import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@Component
@RefreshScope
public class CommonConfig {
@NacosValue(value = "${spring.datasource.username}",autoRefreshed = true)
private String username;
// @Value(value = "${spring.datasource.username}")
// private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
Application
package lmcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
2.6 按profile拉取配置===
背景:nacos里的DataId有两个,一个test.properties,一个test;test.properties的优先级高一点
使用SpringCloud拉取配置时默认情况下,会拉取DEFAULT_GROUP
下DataId
为test.properties
的配置
在使用Spring-cloud-starter-alibaba-nacos-config时一些别的配置项:
bootstrap.properties
spring.application.name=test
spring.cloud.nacos.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.group(默认"DEFAULT_GROUP")
spring.cloud.nacos.config.file-extension(默认"properties")
spring.cloud.nacos.config.prefix(默认"spring.application.name")
2.7 拉取多个配置
两个功能是一样的,可以加很多配置【1.2.3】
相当于一种约束,
3、服务管理
服务管理的核心就是服务注册和服务发现,通过nacos的服务注册和服务发现可以在调用微服务的时候更加简单
3.11 Java SDK进行服务实例的注册
Nacos服务注册 Java SDK的依赖
<!--Nacos服务注册 Java SDK-->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.2.1</version>
</dependency>
同一个服务注册多个实例并配置多个集群
JavaSDK_ServiceRegister
package com.serviceRegister;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
public class JavaSDK_ServiceRegister {
public static void main(String[] args) throws Exception {
NamingService namingService = NamingFactory.createNamingService("127.0.0.1:8848");
namingService.registerInstance("user-service","11.11.11.11",8888,"beijing");
NamingService namingService2 = NamingFactory.createNamingService("127.0.0.1:8848");
namingService2.registerInstance("user-service","11.11.11.12",8888,"shanghai");
NamingService namingService3 = NamingFactory.createNamingService("127.0.0.1:8848");
namingService3.registerInstance("user-service","11.11.11.13",8888,"shanghai");
System.in.read();
}
}
Nacos控制台
3.12 Java SDK进行服务注册方法2
JavaSDK_ServiceRegister2
package com.serviceRegister;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import java.util.HashMap;
import java.util.Map;
public class JavaSDK_ServiceRegister2 {
public static void main(String[] args) throws Exception {
NamingService namingService = NamingFactory.createNamingService("127.0.0.1:8848");
Instance instance = new Instance();
instance.setIp("11.11.11.11");
instance.setPort(8888);
instance.setHealthy(false);
instance.setWeight(0.5);
Map<String ,String> instanceMeta = new HashMap<String,String>();
instanceMeta.put("site","et2");
instance.setMetadata(instanceMeta);
namingService.registerInstance("user-service",instance);
System.in.read();
}
}
Nacos控制台
3.21 Java SDK进行服务发现
JavaSDK_ServiceFind
package com.serviceRegister;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
public class JavaSDK_ServiceFind {
public static void main(String[] args) throws Exception {
NamingService namingService = NamingFactory.createNamingService("127.0.0.1:8848");
/*获取所有实例*/
System.out.println(namingService.getAllInstances("user-service"));
/*所有健康的实例*/
System.out.println(namingService.selectInstances("user-service",true));
/*某一个健康的实例(权重随机算法)*/
System.out.println(namingService.selectOneHealthyInstance("user-service"));
}
}
控制台输出
[Instance{instanceId='null', ip='11.11.11.11', port=8888, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='beijing', serviceName='DEFAULT_GROUP@@user-service', metadata={}}, Instance{instanceId='null', ip='11.11.11.13', port=8888, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='shanghai', serviceName='DEFAULT_GROUP@@user-service', metadata={}}, Instance{instanceId='null', ip='11.11.11.12', port=8888, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='shanghai', serviceName='DEFAULT_GROUP@@user-service', metadata={}}, Instance{instanceId='null', ip='11.11.11.11', port=8888, weight=0.5, healthy=false, enabled=true, ephemeral=true, clusterName='DEFAULT', serviceName='DEFAULT_GROUP@@user-service', metadata={site=et2}}]
[Instance{instanceId='null', ip='11.11.11.11', port=8888, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='beijing', serviceName='DEFAULT_GROUP@@user-service', metadata={}}, Instance{instanceId='null', ip='11.11.11.13', port=8888, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='shanghai', serviceName='DEFAULT_GROUP@@user-service', metadata={}}, Instance{instanceId='null', ip='11.11.11.12', port=8888, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='shanghai', serviceName='DEFAULT_GROUP@@user-service', metadata={}}]
Instance{instanceId='null', ip='11.11.11.13', port=8888, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='shanghai', serviceName='DEFAULT_GROUP@@user-service', metadata={}}
3.22 Java SDK监听服务
JavaSDK_ServiceListener
package com.serviceRegister;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
public class JavaSDK_ServiceListener {
public static void main(String[] args) throws Exception {
NamingService namingService = NamingFactory.createNamingService("127.0.0.1:8848");
namingService.subscribe("user-service",event -> {
if(event instanceof NamingEvent){
System.out.println(((NamingEvent) event).getServiceName());
System.out.println(((NamingEvent) event).getInstances());
}
});
System.in.read();
}
}
控制台输出
先关闭所有服务然后再启动JavaSDK_ServiceRegister
20:39:32.084 [nacos.publisher-com.alibaba.nacos.client.naming.event.InstancesChangeEvent] DEBUG com.alibaba.nacos.common.notify.NotifyCenter - [NotifyCenter] the com.alibaba.nacos.client.naming.event.InstancesChangeEvent@58d69ab3 will received by com.alibaba.nacos.client.naming.event.InstancesChangeNotifier@72e5a8e
user-service
[Instance{instanceId='null', ip='11.11.11.11', port=8888, weight=0.5, healthy=false, enabled=true, ephemeral=true, clusterName='DEFAULT', serviceName='DEFAULT_GROUP@@user-service', metadata={site=et2}}]
20:39:33.709 [nacos.publisher-com.alibaba.nacos.client.naming.event.InstancesChangeEvent] DEBUG com.alibaba.nacos.common.notify.NotifyCenter - [NotifyCenter] the com.alibaba.nacos.client.naming.event.InstancesChangeEvent@7b2d70c6 will received by com.alibaba.nacos.client.naming.event.InstancesChangeNotifier@72e5a8e
user-service
[]
20:40:43.198 [nacos.publisher-com.alibaba.nacos.client.naming.event.InstancesChangeEvent] DEBUG com.alibaba.nacos.common.notify.NotifyCenter - [NotifyCenter] the com.alibaba.nacos.client.naming.event.InstancesChangeEvent@2a886450 will received by com.alibaba.nacos.client.naming.event.InstancesChangeNotifier@72e5a8e
user-service
[Instance{instanceId='null', ip='11.11.11.11', port=8888, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='beijing', serviceName='DEFAULT_GROUP@@user-service', metadata={}}, Instance{instanceId='null', ip='11.11.11.13', port=8888, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='shanghai', serviceName='DEFAULT_GROUP@@user-service', metadata={}}, Instance{instanceId='null', ip='11.11.11.12', port=8888, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='shanghai', serviceName='DEFAULT_GROUP@@user-service', metadata={}}]
3.3 Spring/SpringBoot服务注册与服务发现
直接使用Java SDK的方式进行服务注册和发现比较困难,在Spring和SpringBoot中也不怎么方便
官网地址:https://nacos.io/zh-cn/docs/quick-start-spring-boot.html
3.4 SpringCloud服务注册
pom.xml
<!--SpringCloud 服务注册和发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.8.RELEASE</version>
</dependency>
bootstrap.properties
server.port=9091
spring.application.name=provider
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
单独使用配置中心的地址也可以,分开写可以区分注册中心和配置中心
spring.cloud.nacos.server-addr=127.0.0.1:8848
启动类使用
@EnableDiscoveryClient
开启服务注册
MyApplication
package com.lmcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class,args);
}
}
服务提供者的方法
package com.lmcode.ccontroller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@GetMapping("/provider")
public String provider(){
return "provider";
}
}
3.4 SpringCloud服务发现
pom.xml
<!--SpringCloud 服务注册和发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.8.RELEASE</version>
</dependency>
application.properties
server.port=9092
spring.application.name=consumer
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
通过定义一个RestTemplate发送http请求并调用服务
Application
package com.lmcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
public class Application {
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
ConsumerController
package com.lmcode.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/consumer")
public String echo(){
// provider服务的provider方法
return restTemplate.getForObject("http://provider/provider",String.class);
}
}