手写Nacos基本原理——服务注册 配置管理

简介: 手写Nacos基本原理——服务注册 配置管理

手写Nacos基本原理


一、背景介绍

之前在项目开发的过程中,对于Nacos的理解停留在实际运用层面。但是仅仅停留在运用层面是不够的。所以就对nacos的基本原理进行了理论学习,并且对nacos的服务注册包括健康检查机制(心跳机制),nacos的配置管理进行了代码实现。

二、 思路方案

项目整体结构:1.有服务A和服务B分别集成了nacosSDK(类似与此前的项目引入了nacos的相关依赖);2.nacosService服务端中分别有两个核心的服务注册和配置管理。


三、过程

项目框架为spring boot框架

nacosService代码

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>client</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

配置文件

server:
  port: 8200

具体类

package com.wangwei.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class nacosServiceApplication {
  public static void main(String[] args) {
    SpringApplication.run(nacosServiceApplication.class, args);
  }
}
package com.wangwei.client;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : RestTemplateConfig
 * @description : [RestTemplateConfig配置类创建一个RestTemplate Bean,并在其上配置一些属性,如连接超时时间、读取超时时间等。这些属性将影响RestTemplate的行为]
 * @createTime : [2023/4/15 20:15]
 * @updateUser : [WangWei]
 * @updateTime : [2023/4/15 20:15]
 * @updateRemark : [描述说明本次修改内容]
 */
@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofSeconds(1000))
                .setReadTimeout(Duration.ofSeconds(1000))
                .build();
    }
}
package com.wangwei.client;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : com.wangwei.client.ConfigController
 * @description : [描述说明该类的功能]
 * @createTime : [2023/6/5 20:23]
 * @updateUser : [WangWei]
 * @updateTime : [2023/6/5 20:23]
 * @updateRemark : [描述说明本次修改内容]
 */
@RestController
@RequestMapping("/nacosService")
public class ServeController {
    @Autowired
    RestTemplate restTemplate;
    Map<Object, Map<Object, Object>> registerMap = new HashMap<>();
    Map<Object, Map<Object, Object>> configMap = new HashMap<>();
    /*
     * @description:获取配置信息
     * @author: wangwei
     * @date: 2023/7/21 17:13
     * @param: []
     * @return: java.util.Map<java.lang.Object,java.lang.Object>
     **/
    @GetMapping("/getConfig")
    public Map<Object,Object> getConfig(){
        Map<Object,Object>configurationInfo=new HashMap<>();
        for (Map.Entry<Object,Map<Object,Object>> map:configMap.entrySet()) {
            Object mapKey = map.getKey();
            Map<Object, Object> value = map.getValue();
            configurationInfo.put(mapKey,value);
        }
        return configurationInfo;
    }
    /*
     * @description:获取注册信息
     * @author: wangwei
     * @date: 2023/7/21 17:12
     * @param: []
     * @return: java.util.Map<java.lang.Object,java.lang.Object>
     **/
    @GetMapping("/getRegister")
    public  Map<Object, Object> getRegister(){
        Map<Object,Object>registrationInfo=new HashMap<>();
        for (Map.Entry<Object,Map<Object,Object>> map:registerMap.entrySet()) {
            Object mapKey = map.getKey();
            Map<Object, Object> value = map.getValue();
            registrationInfo.put(mapKey,value);
        }
        return registrationInfo;
    }
    /*
     * @description:进行服务注册
     * @author: wangwei
     * @date: 2023/7/21 17:07
     * @param: [registMap]
     * @return: java.lang.String
     **/
    @PostMapping("/regist")
    public String regist(@RequestBody Map<Object,Object> registMap){
        registerMap.put( registMap.get("serviceName"), (Map<Object, Object>) registMap.get("serviceValue"));
        this.notice();
        System.out.println(registMap);
        Map<Object ,Object> serviceValue =(Map<Object, Object>) registMap.get("serviceValue");
        //服务注册成功之后为该服务开启心跳定时任务
        this.heartBeatTask(serviceValue);
        return "服务注册成功!!!";
    }
    /*
     * @description:根据注册表中的注解信息通知对应的服务
     * @author: wangwei
     * @date: 2023/7/22 8:21
     * @param: [registMap]
     * @return: void
     **/
    public void notice() {
        for (Map.Entry<Object, Map<Object, Object>> entry : registerMap.entrySet()) {
            Map<Object, Object> value = entry.getValue();
            String ip= value.get("ipAddress")+":"+value.get("port");
            String url = "http://"+ip+"/getRegisterInfo";
            System.out.println(registerMap);
            restTemplate.getForObject(url,Map.class);
        }
    }
    /*
     * @description:修改配置信息并通知给对应的服务,来获取最新的配置
     * @author: wangwei
     * @date: 2023/7/21 11:13
     * @param: [config]
     * @return: java.lang.String
     **/
    @PostMapping("/setConfig")
    public String setConfig(@RequestBody Map<String,Object> configInfo) {
        configMap.put( configInfo.get("serviceName"), (Map<Object,Object>) configInfo.get("serviceValue"));
        if(registerMap.containsKey(String.valueOf(configInfo.get("serviceName")))) {
            Map<Object,Object> registrationInfo = registerMap.get(String.valueOf(configInfo.get("serviceName")));
            String ip= registrationInfo.get("ipAddress")+":"+registrationInfo.get("port");
            String url = "http://"+ip+"/getConfigInfo";
            //通知对应的服务
            restTemplate.getForObject(url,Map.class);
        }
        System.out.println(configInfo);
        return "配置注册成功!!!";
    }
    /*
     * @description:给注册上的服务开启心跳任务
     * @author: wangwei
     * @date: 2023/7/22 8:32
     * @param: [registrationInfo]
     * @return: void
     **/
    private void heartBeatTask(Map<Object,Object> registrationInfo) {
        // 创建一个定时任务调度器,该调度器可以执行定时任务
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        CountDownLatch latch = new CountDownLatch(1); // 创建一个CountDownLatch,初始值为1
        String ip = registrationInfo.get("ipAddress") + ":" + registrationInfo.get("port");
        String url ="http://"+ ip + "/heartBeatCheck";
        // 定义一个心跳任务,使用匿名内部类实现Runnable接口
        Runnable heartbeatTask = new Runnable() {
            @Override
            public void run() {
                try {
                    restTemplate.getForObject(url, boolean.class);
                    System.out.println("心跳检查" + ip);
                } catch (Exception e) {
                    // 关闭定时任务调度器
                    scheduler.shutdown();
                    // 将该服务从注册表中删除
                    registerMap.remove(registrationInfo.get("serviceName"));
                    //通知注册表中的其他服务,来获取最细的注册表信息
                    notice();
                }
            }
        };
        // 使用定时任务调度器,每5秒执行一次心跳任务,并将ScheduledFuture对象传递给任务
         scheduler.scheduleAtFixedRate(heartbeatTask, 0, 5, TimeUnit.SECONDS);
    }
}

nacosSDK代码

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wangwei</groupId>
    <artifactId>nacosSDK</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

配置类

server:
  port: 8100

具体类

package com.wangwei.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class nacosSDKApplication {
  public static void main(String[] args) {
    SpringApplication.run(nacosSDKApplication.class, args);
  }
}
package com.wangwei.client;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : RestTemplateConfig
 * @description : [RestTemplateConfig配置类创建一个RestTemplate Bean,并在其上配置一些属性,如连接超时时间、读取超时时间等。这些属性将影响RestTemplate的行为]
 * @createTime : [2023/4/15 20:15]
 * @updateUser : [WangWei]
 * @updateTime : [2023/4/15 20:15]
 * @updateRemark : [描述说明本次修改内容]
 */
@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofSeconds(1000))
                .setReadTimeout(Duration.ofSeconds(1000))
                .build();
    }
}
package com.wangwei.client;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : ServerConfig
 * @description : [程序启动时执行]
 * @createTime : [2023/6/6 19:49]
 * @updateUser : [WangWei]
 * @updateTime : [2023/6/6 19:49]
 * @updateRemark : [描述说明本次修改内容]
 */
@Component
public class ServerConfig implements ApplicationRunner {
    @Value("${server.name}")
    private String name;
    @Value("${server.port}")
    private String port;
    @Value("${server.nacosUrl}")
    private String nacosUrl;
    @Autowired
    private RestTemplate restTemplate;
    /*
     * @description:程序启动之后该方法,将服务注册到nacos的注册中心
     * @author: wangwei
     * @date: 2023/7/21 10:42
     * @param: [args]
     * @return: void
     **/
    @Override
    public void run(ApplicationArguments args) throws Exception {
        String ipAddress=null;
        //获取本机的ip地址
        ipAddress = InetAddress.getLocalHost().getHostAddress();
        // 构建请求体
        Map<Object, Object> requestBody = new HashMap<>();
        requestBody.put("serviceName",name);
        Map<String, Object> serviceValue = new HashMap<>();
        serviceValue.put("ipAddress", ipAddress);
        serviceValue.put("port", this.port);
        serviceValue.put("serviceName",name);
        requestBody.put("serviceValue",serviceValue);
        // 发送POST请求
        String url = "http://"+nacosUrl+"/nacosService/regist";
        String response = restTemplate.postForObject(url, requestBody, String.class);
        System.out.println("已经注册到nacos中"+response);
    }
}
package com.wangwei.client;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : com.wangwei.client.ConfigController
 * @description : [描述说明该类的功能]
 * @createTime : [2023/6/5 20:23]
 * @updateUser : [WangWei]
 * @updateTime : [2023/6/5 20:23]
 * @updateRemark : [描述说明本次修改内容]
 */
@RestController
public class ConfigController {
    @Value("${server.name}")
    private String name;
    @Value("${server.nacosUrl}")
    private String nacosUrl;
   public Map<Object,Object>configMap=new HashMap<>();
   public Map<Object,Object>registerMap=new HashMap<>();
    public Map<Object, Object> getConfigMap() {
        return configMap;
    }
    public void setConfigMap(Map<Object, Object> configMap) {
        this.configMap = configMap;
    }
    public Map<Object, Object> getRegisterMap() {
        return registerMap;
    }
    public void setRegisterMap(Map<Object, Object> registerMap) {
        this.registerMap = registerMap;
    }
    @Autowired
    RestTemplate restTemplate;
    /**
     * @description:从serve中获取配置信息
     * @author: wangwei
     * @date: 2023/6/5 20:57
     * @param: []
     * @return: void
     **/
    @GetMapping("/getConfigInfo")
    public Map<Object, Object> getConfig(){
        // 发送 GET 请求
        // 定义请求的URL和参数
        String url = "http://"+nacosUrl+"/nacosService/getConfig";
        Map<Object,Object>response = (Map<Object, Object>) restTemplate.getForObject(url, Map.class);
        configMap.clear();
        configMap.putAll(response);
        return configMap;
    }
    //获取注册信息
    @GetMapping("/getRegisterInfo")
    public  Map<Object, Object> getRegister(){
        // 发送 GET 请求
        // 定义请求的URL和参数
        String url = "http://"+nacosUrl+"/nacosService/getRegister";
        Map<Object,Object>response = (Map<Object, Object>) restTemplate.getForObject(url, Map.class);
        //将过期的缓存注册表信息清空
        registerMap.clear();
        registerMap.putAll(response);
        System.out.println("已经更新最新的注册表信息"+registerMap);
        return registerMap;
    }
    /*
     * @description:更具服务名称,返回服务的ip
     * @author: wangwei
     * @date: 2023/7/25 8:30
     * @param: [serviceName]
     * @return: java.lang.String
     **/
    @GetMapping("/getIp{serviceName}")
    public String getIp(@PathVariable String serviceName){
        Map<Object, Object> objectMap = (Map<Object, Object>)registerMap.get(serviceName);
        String ip=objectMap.get("ipAddress")+":"+objectMap.get("port");
        return ip;
    }
    /*
     * @description:心跳检查
     * @author: wangwei
     * @date: 2023/7/21 16:01
     * @param: []
     * @return: boolean
     **/
    @GetMapping("/heartBeatCheck")
    public boolean heartBeatCheck(){
        return true;
    }
}

serviceA代码

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>serviceA</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>NacosService</name>
    <description>NacosService</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- nacosSDK依赖-->
        <dependency>
            <groupId>com.wangwei</groupId>
            <artifactId>nacosSDK</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

配置文件

server:
  name: serviceA
  port: 8300
  nacosUrl: 192.168.109.60:8200

具体类

package com.wangwei.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ServiceAApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceAApplication.class, args);
    }
}
package com.wangwei.client;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : RestTemplateConfig
 * @description : [RestTemplateConfig配置类创建一个RestTemplate Bean,并在其上配置一些属性,如连接超时时间、读取超时时间等。这些属性将影响RestTemplate的行为]
 * @createTime : [2023/4/15 20:15]
 * @updateUser : [WangWei]
 * @updateTime : [2023/4/15 20:15]
 * @updateRemark : [描述说明本次修改内容]
 */
@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofSeconds(1000))
                .setReadTimeout(Duration.ofSeconds(1000))
                .build();
    }
}
package com.wangwei.client;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
@RestController
@RequestMapping("/serviceA")
public class ServiceA {
    @Autowired
    ConfigController configController;
    @Autowired
    RestTemplate restTemplate;
    /*
     * @description:获取该服务的配置信息
     * @author: wangwei
     * @date: 2023/7/21 20:57
     * @param: []
     * @return: java.util.Map<java.lang.Object,java.lang.Object>
     **/
    @GetMapping("/getConfigInfo")
    public Map<Object,Object> getConfig(){
        Map<Object, Object> config = configController.getConfig();
        Map <Object,Object> configurationInfo= (Map<Object, Object>) config.get("serviceA");
        // 打印目标Map中的值
        for (Map.Entry<Object, Object> entry : configurationInfo.entrySet()) {
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
        }
        return config;
    }
    /*
     * @description:从注册表中获取注册信息
     * @author: wangwei
     * @date: 2023/7/21 20:56
     * @param: []
     * @return: java.util.Map<java.lang.Object,java.lang.Object>
     **/
    @GetMapping("/getRegister")
    public Map<Object,Object> Register() {
        Map<Object, Object> register = configController.getRegister();
        // 打印目标Map中的值
        for (Map.Entry<Object, Object> entry : register.entrySet()) {
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
        }
        return register;
    }
    @GetMapping("/sendMessageToB")
    public String sendMessageToB(){
        String ip = configController.getIp("serviceB");
        // 定义请求的URL和参数
        String url = "http://"+ip+"/serviceB/test";
        // 发送 GET 请求并获取响应
        ResponseEntity<String> response = restTemplate.getForEntity(url,String.class);
        // 获取响应结果
        if (response.getStatusCode().is2xxSuccessful()) {
            Object responseBody = response.getBody();
            System.out.println("Response: " + responseBody);
        } else {
            System.out.println("Request failed with status code: " + response.getStatusCodeValue());
        }
        return "给B发送消息成功!!!";
    }
}

serviceB代码

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>ServiceB</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>NacosService</name>
    <description>NacosService</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--nacosSDK-->
        <dependency>
            <groupId>com.wangwei</groupId>
            <artifactId>nacosSDK</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

配置文件

server:
  name: serviceB
  port: 8500
  nacosUrl: 192.168.109.60:8200

具体类

package com.wangwei.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ServiceBApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceBApplication.class, args);
    }
}
package com.wangwei.client;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : RestTemplateConfig
 * @description : [RestTemplateConfig配置类创建一个RestTemplate Bean,并在其上配置一些属性,如连接超时时间、读取超时时间等。这些属性将影响RestTemplate的行为]
 * @createTime : [2023/4/15 20:15]
 * @updateUser : [WangWei]
 * @updateTime : [2023/4/15 20:15]
 * @updateRemark : [描述说明本次修改内容]
 */
@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(Duration.ofSeconds(1000))
                .setReadTimeout(Duration.ofSeconds(1000))
                .build();
    }
}
package com.wangwei.client;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
@RestController
@RequestMapping("/serviceB")
public class ServiceB {
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    ConfigController configController;
    /*
     * @description:获取该服务的配置信息
     * @author: wangwei
     * @date: 2023/7/21 20:57
     * @param: []
     * @return: java.util.Map<java.lang.Object,java.lang.Object>
     **/
    @GetMapping("/getConfig")
    public Map<Object,Object> getConfig(){
        Map<Object, Object> config = configController.getConfig();
        Map <Object,Object> configurationInfo= (Map<Object, Object>) config.get("serviceB");
        // 打印目标Map中的值
        for (Map.Entry<Object, Object> entry : configurationInfo.entrySet()) {
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
        }
        return config;
    }
    @GetMapping("/getRegister")
    public Map<Object,Object> Register() {
        Map<Object, Object> register = configController.getRegister();
        // 打印目标Map中的值
        for (Map.Entry<Object, Object> entry : register.entrySet()) {
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
        }
        return register;
    }
    @GetMapping("/test")
    public void testA(){
        System.out.println("我被A服务调用了");
    }
}

实现效果

先启动nacosService,再依次启动serviceB、serviceA。

  1. 服务启动时注册到nacos的服务管理中

serviceA:

serviceB:

2. 服务注册成功之后后,nacosService为该实例创建一个心跳定时任务,服务需要定期向nacos注册中心发送心跳请求,如果没有收到心跳请求则将该服务信息从注册表中删除。

nacosService:

这个时候一旦有服务挂掉,会将该服务的注册信息进行删除,并将最新的注册信息同步给其他服务。

例如:serviceA挂掉了

nacosService:

serviceB:


  1. 修改配置信息会通知服务来来获取最新的配置信息
  2. A请求B时,将B的服务名称在nacosSDK中转换为实际B服务的ip+端口号进行请求

    ServiceB:

四、总结

  1. 理论和实践的结合,才能反过来指导理论。
  2. 本篇博客只是简单的实现了nacos的注册中心和配置管理,nacos还有很多的功能模块,并且本篇博客对于代码的健壮性是没有进行考虑的。
  3. 能够将nacos的基本原理进行理解,并通过代码实现。需要感谢马总的指导和帮助。并且本篇博客也借鉴了马总的总结。例如通过以图形的方式来表示清晰简洁的表现思路、服务之间的依赖关系。我都从中学习了很多,这也侧面说明了学习是一个反复的过程。

五、升华

站在巨人的肩膀上学习。

不将就就是发现的原动力。

目录
相关文章
|
2月前
|
存储 Nacos 数据安全/隐私保护
【SpringCloud】Nacos的安装、Nacos注册、Nacos服务多级存储模型
【SpringCloud】Nacos的安装、Nacos注册、Nacos服务多级存储模型
51 1
|
23天前
|
Java Nacos 数据格式
Spring Cloud Nacos 详解:服务注册与发现及配置管理平台
Spring Cloud Nacos 详解:服务注册与发现及配置管理平台
62 3
|
3天前
|
负载均衡 Java Linux
黑马头条01,环境搭建,今日头条的介绍,今日头条的功能架构图,技术栈的说明,服务层,nacos(奶靠丝)安装,安装在Linux服务器上环境准备,
黑马头条01,环境搭建,今日头条的介绍,今日头条的功能架构图,技术栈的说明,服务层,nacos(奶靠丝)安装,安装在Linux服务器上环境准备,
|
8天前
|
开发框架 .NET Nacos
使用 Nacos 在 C# (.NET Core) 应用程序中实现高效配置管理和服务发现
使用 Nacos 在 C# (.NET Core) 应用程序中实现高效配置管理和服务发现
20 0
|
9天前
|
JavaScript Java Go
Nacos vs. Eureka:微服务注册中心的对比
Nacos vs. Eureka:微服务注册中心的对比
14 0
|
10天前
|
Java Nacos 微服务
Spring Cloud微服务在Windows本地开发时禁用Nacos注册中心注册
Spring Cloud微服务在Windows本地开发时禁用Nacos注册中心注册
|
11天前
|
SpringCloudAlibaba 负载均衡 Java
SpringCloudAlibaba之nacos的服务注册与发现
如图所示:按照图示搭建一个nacos作为服务注册中心的简单应用.
13 0
|
11天前
|
SpringCloudAlibaba 安全 Java
SpringCloudalibaba之Nacos的配置管理
如图所示,nacos-config-example被192.168.56.1获取过。
15 0
|
11天前
|
Nacos 数据安全/隐私保护
springCloud之nacos服务注册与发现、配置中心
springCloud之nacos服务注册与发现、配置中心
21 0
|
2月前
|
监控 Nacos Docker
【开发问题记录】Nacos修改服务实例权重时报错
【开发问题记录】Nacos修改服务实例权重时报错
60 1