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 新建配置

image

image


在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控制台修改配置控制台会同步打印修改后的配置

image
image

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拉取配置与自动刷新


image

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);
    }
}

结果展示

image

报错修改: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

image

配置方式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

image

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_GROUPDataIdtest.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")

image

image

image

image

image

2.7 拉取多个配置

image

两个功能是一样的,可以加很多配置【1.2.3】

image

https://www.bilibili.com/video/BV1q3411Z79z?p=9&spm_id_from=pageDriver&vd_source=1a563cd2b3f3fdeb2a16cbbf18022d2f

image

相当于一种约束,

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控制台

image

image
image

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控制台

image

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);
    }
}

http://localhost:9092/consumer

image

posted @ 2024-04-15 18:59  燕子去了  阅读(28)  评论(0编辑  收藏  举报

Powered by .NET 8.0 on Kubernetes

我会翻山越岭,到每一个我想去的地方

...