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

五、升华

站在巨人的肩膀上学习。

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

目录
相关文章
|
4月前
|
Cloud Native Java Nacos
微服务时代的新宠儿!Spring Cloud Nacos实战指南,带你玩转服务发现与配置管理,拥抱云原生潮流!
【8月更文挑战第29天】Spring Cloud Nacos作为微服务架构中的新兴之星,凭借其轻量、高效的特点,迅速成为服务发现、配置管理和治理的首选方案。Nacos(命名和配置服务)由阿里巴巴开源,为云原生应用提供了动态服务发现及配置管理等功能,简化了服务间的调用与依赖管理。本文将指导你通过五个步骤在Spring Boot项目中集成Nacos,实现服务注册、发现及配置动态管理,从而轻松搭建出高效的微服务环境。
292 0
|
1月前
|
网络安全 Nacos 开发者
Nacos作为流行的微服务注册与配置中心,“节点提示暂时不可用”是常见的问题之一
Nacos作为流行的微服务注册与配置中心,其稳定性和易用性备受青睐。然而,“节点提示暂时不可用”是常见的问题之一。本文将探讨该问题的原因及解决方案,帮助开发者快速定位并解决问题,确保服务的正常运行。通过检查服务实例状态、网络连接、Nacos配置、调整健康检查策略等步骤,可以有效解决这一问题。
35 4
|
1月前
|
Java 网络安全 Nacos
Nacos作为流行的微服务注册与配置中心,其稳定性和易用性备受青睐。
Nacos作为流行的微服务注册与配置中心,其稳定性和易用性备受青睐。然而,实际使用中常遇到“客户端不发送心跳检测”的问题。本文深入探讨该问题的原因及解决方案,帮助开发者快速定位并解决问题,确保服务正常运行。通过检查客户端配置、网络连接、日志、版本兼容性、心跳策略、注册状态、重启应用和环境变量等步骤,系统地排查和解决这一问题。
48 3
|
1月前
|
安全 Nacos 数据库
Nacos是一款流行的微服务注册与配置中心,但直接暴露在公网中可能导致非法访问和数据库篡改
Nacos是一款流行的微服务注册与配置中心,但直接暴露在公网中可能导致非法访问和数据库篡改。本文详细探讨了这一问题的原因及解决方案,包括限制公网访问、使用HTTPS、强化数据库安全、启用访问控制、监控和审计等步骤,帮助开发者确保服务的安全运行。
40 3
|
2月前
|
负载均衡 算法 Java
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?
40岁老架构师尼恩分享了关于SpringCloud核心组件的底层原理,特别是针对蚂蚁集团面试中常见的面试题进行了详细解析。内容涵盖了Nacos注册中心的AP/CP模式、Distro和Raft分布式协议、Sentinel的高可用组件、负载均衡组件的实现原理等。尼恩强调了系统化学习的重要性,推荐了《尼恩Java面试宝典PDF》等资料,帮助读者更好地准备面试,提高技术实力,最终实现“offer自由”。更多技术资料和指导,可关注公众号【技术自由圈】获取。
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?
|
1月前
|
数据管理 Nacos 开发者
"Nacos架构深度解析:一篇文章带你掌握业务层四大核心功能,服务注册、配置管理、元数据与健康检查一网打尽!"
【10月更文挑战第23天】Nacos 是一个用于服务注册发现和配置管理的平台,支持动态服务发现、配置管理、元数据管理和健康检查。其业务层包括服务注册与发现、配置管理、元数据管理和健康检查四大核心功能。通过示例代码展示了如何在业务层中使用Nacos,帮助开发者构建高可用、动态扩展的微服务生态系统。
87 0
|
1月前
|
SQL 关系型数据库 数据库连接
"Nacos 2.1.0版本数据库配置写入难题破解攻略:一步步教你排查连接、权限和配置问题,重启服务轻松解决!"
【10月更文挑战第23天】在使用Nacos 2.1.0版本时,可能会遇到无法将配置信息写入数据库的问题。本文将引导你逐步解决这一问题,包括检查数据库连接、用户权限、Nacos配置文件,并提供示例代码和详细步骤。通过这些方法,你可以有效解决配置写入失败的问题。
60 0
|
3月前
|
Kubernetes Nacos 容器
nacos注册不上
我正在使用开源的Nacos,并已在Kubernetes中部署了Nacos服务,通过端口映射可在集群外访问Nacos控制台。Kubernetes使用NodePort类型暴露了8848、9848、9849、7848和9555端口,但在尝试注册时遇到问题,出现“Client not connected, current status: STARTING”的错误,导致启动失败。
|
4月前
|
Java Nacos Docker
"揭秘!Docker部署Seata遇上Nacos,注册成功却报错?这些坑你不得不防!一网打尽解决秘籍,让你的分布式事务稳如老狗!"
【8月更文挑战第15天】在微服务架构中,Nacos搭配Seata确保数据一致性时,Docker部署Seata后可能出现客户端连接错误,如“can not connect to services-server”。此问题多由网络配置不当、配置文件错误或版本不兼容引起。解决策略包括:调整Docker网络设置确保可达性;检查并修正`file.conf`和`registry.conf`中的Nacos地址和端口;验证Seata与Nacos版本兼容性;修改配置后重启服务;参考官方文档和最佳实践进行配置。通过这些步骤,能有效排除故障,保障服务稳定运行。
314 0
|
4月前
|
Kubernetes Nacos 微服务
【技术难题破解】Nacos v2.2.3 + K8s 微服务注册:强制删除 Pod 却不消失?!7步排查法+实战代码,手把手教你解决Nacos Pod僵死问题,让服务瞬间满血复活!
【8月更文挑战第15天】Nacos作为微服务注册与配置中心受到欢迎,但有时会遇到“v2.2.3 k8s 微服务注册nacos强制删除 pod不消失”的问题。本文介绍此现象及其解决方法,帮助开发者确保服务稳定运行。首先需检查Pod状态与事件、配置文件及Nacos配置,确认无误后可调整Pod生命周期管理,并检查Kubernetes版本兼容性。若问题持续,考虑使用Finalizers、审查Nacos日志或借助Kubernetes诊断工具。必要时,可尝试手动强制删除Pod。通过系统排查,通常能有效解决此问题。
83 0