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

news2024/10/6 6:04:33

手写Nacos基本原理

  • 一、背景介绍
  • 二、 思路方案
  • 三、过程
    • nacosService代码
      • pom文件
      • 配置文件
      • 具体类
    • nacosSDK代码
      • pom文件
      • 配置类
      • 具体类
    • serviceA代码
      • pom文件
      • 配置文件
      • 具体类
    • serviceB代码
      • pom文件
      • 配置文件
      • 具体类
  • 实现效果
  • 四、总结
  • 五、升华

一、背景介绍

之前在项目开发的过程中,对于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的基本原理进行理解,并通过代码实现。需要感谢马总的指导和帮助。并且本篇博客也借鉴了马总的总结。例如通过以图形的方式来表示清晰简洁的表现思路、服务之间的依赖关系。我都从中学习了很多,这也侧面说明了学习是一个反复的过程。

五、升华

站在巨人的肩膀上学习。
不将就就是发现的原动力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/784324.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java 贪心算法经典问题解决

文章目录 分金条题目思路代码实现测试用例以及结果输出 花费资金做项目最大收益题目思路代码实现测试用例以及结果输出 预定会议室题目思路代码实现测试用例以及结果输出 取中位数题目思路代码实现测试用例以及结果输出 最低字典序题目思路代码实现测试用例以及结果输出 结语 分…

如何在工作中利用Prompt高效使用ChatGPT

导读 AI 不是来替代你的&#xff0c;是来帮助你更好工作。用better prompt使用chatgpt&#xff0c;替换搜索引擎&#xff0c;让你了解如何在工作中利用Prompt高效使用ChatGPT。 01背景 现在 GPT 已经开启了人工智能狂潮&#xff0c;不过是IT圈&#xff0c;还是金融圈。 一开…

【线性规划、非线性规划、多目标规划】

有限的条件下&#xff0c;最大的收益 线性规划就是在一组线性约束条件下&#xff0c;求线性目标函数的最大或者最小值 线性就是指所有的变量都是一次方 整数规划、0-1规划都是默认为线性规划的特例 MATLAB自带的函数求解线性规划问题&#xff1a; Linprog函数 模型化为MATL…

docker+Jenkins

拉取镜像 docker pull jenkins/jenkins启动容器 8080端口映射58080 jenkins_home 映射本地/data/下方便查看 docker run -d -p 58080:8080 -p 5000:50000 -v /data/jenkins_home:/var/jenkins_home -v /etc/localtime:/etc/localtime --name jenkins jenkins/jenkins访问ip:5…

线性神经网路——线性回归随笔【深度学习】【PyTorch】【d2l】

文章目录 3.1、线性回归3.1.1、PyTorch 从零实现线性回归3.1.2、简单实现线性回归 3.1、线性回归 线性回归是显式解&#xff0c;深度学习中绝大多数遇到的都是隐式解。 3.1.1、PyTorch 从零实现线性回归 %matplotlib inline import random import torch #d2l库中的torch模块&a…

前端密码加密 —— bcrypt、MD5、SHA-256、盐

&#x1f414; 前期回顾悄悄告诉你&#xff1a;前端如何获取本机IP&#xff0c;轻松一步开启网络探秘之旅_彩色之外的博客-CSDN博客前端获取 本机 IP 教程https://blog.csdn.net/m0_57904695/article/details/131855907?spm1001.2014.3001.5501 在前端密码加密方案中&#xff…

开发一个RISC-V上的操作系统(三)—— 串口驱动程序(UART)

目录 文章传送门 一、什么是串口 二、本项目串口的FPGA实现 三、串口驱动程序的编写 四、上板测试 文章传送门 开发一个RISC-V上的操作系统&#xff08;一&#xff09;—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统&#xff08;二&…

Linux-定时清除日志No space left on device

由于开发环境上一般机器资源较少&#xff0c;很容易导致因日志文件过大而导致系统宕机&#xff0c;报错No space left on device等问题&#xff0c;我们可以通过添加定时任务&#xff0c;自动删除日志从而达到节省空间的目的 操作步骤&#xff1a; 云服务器进入救援模式(若服…

目前主流的几个Web前端框架

启动项目时&#xff0c;请查看 2023 年最好的 Web 前端框架。为什么选择合适的工具很重要? 前端开发人员使用前端框架来简化工作。这些软件包通常提供可重用的代码模块、系统化的前端技术和预构建的接口块。这使团队可以更快、更轻松地创建可持续的 Web 应用程序和用户界面&am…

[linux]VI编辑器常用命令

VI编辑器常用命令 命令用法含义dd删除游标所在一整行d1G删除光标所在到第一行的所有数据dG删除光标所在到最后一行的所有数据d$删除光标所在处&#xff0c;到该行的最后一个字符d0那个是数字0,删除光标所在到该行的最前面的一个字符x,Xx向后删除一个字符(相当于[del]按键),X向…

深入浅出多种开发语言对接淘宝京东1688阿里巴巴等电商平台,获取实时商品详情数据API接口介绍

api接口详解大全?优秀的设计是产品变得卓越的原因设计API意味着提供有效的接口&#xff0c;可以帮助API使用者更好地了解、使用和集成&#xff0c;同时帮助人们有效地维护它每个产品都需要使用手册&#xff0c;API也不例外在API领域&#xff0c;可以将设计视为服务器和客户端之…

Oracle中varchar2、clob字段类型中特殊字符会显示为问号解决方法

项目中遇到varchar2、clob字段存储数据&#xff0c;内容中存在特殊字符导致显示问号&#xff0c;以下说明解决此问题的办法 首先我们查询下数据库编码、客户端编码、查询用户操作系统字符集 --查看oracle数据库编码 select * from nls_database_parameters where parameter NL…

MySQL数据库第十一课---------SQl语句的拔高-------水平提升

作者前言 个人主页::小小页面 gitee页面:秦大大 一个爱分享的小博主 欢迎小可爱们前来借鉴 ______________________________________________________ 目录 SQL提高 日期函数 length round reverse substring ifnull case when cast grouping sets 排序函数 开窗函…

从零到一,激活GPU的力量:使用TensorRT量化和CUDA并行编程

TensorRT学习笔记 前情提要&#xff1a;TensorRT 模型优化与推理&#xff1a;从零到一&#xff0c;激活GPU的力量&#xff1a;使用TensorRT优化和执行深度学习模型&#xff0c;你的TensorRT入门指南 本篇将会介绍TensorRT下的模型量化与CUDA并行计算编程的介绍。 TensorRT模型…

【雕爷学编程】Arduino动手做(170)---LGT8F328P 开发板

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

如何在3ds max中创建可用于真人场景的巨型机器人:第 2 部分

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 创建主体 步骤 1 打开 3ds Max。选择机器人头部后&#xff0c;二次单击鼠标并选择隐藏未选中。机器人的其他部分 除了头部之外&#xff0c;将被隐藏。 打开 3ds Max 步骤 2 在人脸选择模式下&#x…

自动化测试项目实战

目录 1.熟悉项目 2.针对核心流程设计手工测试用例 3.手工测试用例转换为自动化测试用例 前置工作 测试工作 登陆界面 博客列表页数量 博客详情页检验 写博客并发布 校验标题&#xff0c;时间 删除博客 注销博客 针对博客系统进行自动化测试 1.熟悉项目 2.针对核…

2023年9月北京/广州/深圳CDGA/CDGP认证考试报名开启

据DAMA中国官方网站消息&#xff0c;2023年度第三期DAMA中国CDGA和CDGP认证考试定于2023年9月23日举行。 报名通道现已开启&#xff0c;相关事宜通知如下&#xff1a; 考试科目: 数据治理工程师(CertifiedDataGovernanceAssociate,CDGA) 数据治理专家(CertifiedDataGovernanc…

AlSD 系列智能安全配电装置是安科瑞电气有限公司专门为低压配电侧开发的一款智能安全用电产 品-安科瑞黄安南

一、应用背景 电力作为一种清洁能源&#xff0c;给人们带来了舒适、便捷的电气化生活。与此同时&#xff0c;由于使用不当&#xff0c;维护 不及时等原因引发的漏电触电和电气火灾事故&#xff0c;也给人们的生命和财产带来了巨大的威胁和损失。 为了防止低压配电系统发生漏…

数据结构和算法——表排序(算法概述、物理排序、复杂度分析,包含详细清晰图示过程)

目录 算法概述 物理排序 复杂度分析 算法概述 表排序用于 待排元素都为一个庞大的结构&#xff0c;而不是一个简单的数字&#xff0c;例如&#xff1a;一本书&#xff0c;一部电影等等。 如果这些待排元素都用之前的排序方法&#xff0c;元素需要频繁互换&#xff0c;那么…