手写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。
- 服务启动时注册到nacos的服务管理中
serviceA:
serviceB:
2. 服务注册成功之后后,nacosService为该实例创建一个心跳定时任务,服务需要定期向nacos注册中心发送心跳请求,如果没有收到心跳请求则将该服务信息从注册表中删除。
nacosService:
这个时候一旦有服务挂掉,会将该服务的注册信息进行删除,并将最新的注册信息同步给其他服务。
例如:serviceA挂掉了
nacosService:
serviceB:
- 修改配置信息会通知服务来来获取最新的配置信息
- A请求B时,将B的服务名称在nacosSDK中转换为实际B服务的ip+端口号进行请求
ServiceB:
四、总结
- 理论和实践的结合,才能反过来指导理论。
- 本篇博客只是简单的实现了nacos的注册中心和配置管理,nacos还有很多的功能模块,并且本篇博客对于代码的健壮性是没有进行考虑的。
- 能够将nacos的基本原理进行理解,并通过代码实现。需要感谢马总的指导和帮助。并且本篇博客也借鉴了马总的总结。例如通过以图形的方式来表示清晰简洁的表现思路、服务之间的依赖关系。我都从中学习了很多,这也侧面说明了学习是一个反复的过程。
五、升华
站在巨人的肩膀上学习。
不将就就是发现的原动力。