• 【手写Nacos系列】上厕所的功夫,带你手写一个注册中心的服务注册功能



    上一篇文章 《Nacos是如何实现服务注册功能的》,我们全面解析了Nacos是如何实现服务注册的,那么这篇文章,我们就来手写一个Nacos,完成注册中心的服务注册功能。

    源码在文末

    为了更加贴近Nacos,我们本次总共开发三个模块。

    1. 模拟Nacos客户端【接入微服务】
    2. 模拟Nacos服务端
    3. 生产者微服务【为了测试】

    手写Nacos客户端

    对于这个模块的设计,主要有几下几点:

    1. 编写/META-INF/spring.factories文件加入自动装配类
    2. 将需要的类注入IOC容器
    3. 发布服务注册事件
    4. 监听发布的事件,准备向服务端发送数据

    接下来,看具体实现

    第一步,编写自动装配类

    在这里插入图片描述

    @Configuration(proxyBeanMethods = false)
    @Import(InitRegistrySelect.class)
    public class EnableRegistryConfiguration {
    
        /**
         * 远程调用
         * @return RestTemplate
         */
        @Bean
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }
    

    第二步,将我们需要的类注入IOC容器

    public class InitRegistrySelect implements ImportSelector {
    
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    
    						// 服务注册的事件监听
            return new String[]{"com.ossa.registry.core.OssaRegistry",
            		// 服务注册的事件发布
                    "com.ossa.registry.core.OssaSmartLifecycle",
            // 客户端信息
            "com.ossa.registry.core.ClientInfo"};
        }
    }
    

    客户端信息

    
    @ConfigurationProperties(prefix = "client.info")
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class ClientInfo {
        private String ip;
    
        private String port;
    
        private String namespace;
    
        private String group;
    
        private String dataId;
    
        private String name;
    }
    

    事件

    @Getter
    @Setter
    public class OssaEven extends ApplicationEvent {
    
        private ClientInfo clientInfo;
    
        /**
         * Create a new {@code ApplicationEvent}.
         *
         * @param source the object on which the event initially occurred or with
         *               which the event is associated (never {@code null})
         */
        public OssaEven(Object source,ClientInfo clientInfo) {
            super(source);
            this.clientInfo = clientInfo;
        }
    }
    

    服务注册的事件发布

    public class OssaSmartLifecycle implements SmartLifecycle {
    
        @Autowired
        private ApplicationContext applicationContext;
    
        @Autowired
        private ClientInfo clientInfo;
    
        @Override
        public void start() {
        	// 发布事件
            applicationContext.publishEvent(new OssaEven(this,clientInfo));
        }
    
        @Override
        public void stop() {
    
        }
    
        @Override
        public boolean isRunning() {
            return false;
        }
    
        @Override
        public int getPhase() {
            return SmartLifecycle.super.getPhase();
        }
    }
    

    服务注册的事件监听

    public class OssaRegistry {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @EventListener
        public void registry(OssaEven even) {
            this.sendNacosClientInfo(even.getClientInfo());
        }
    
        private void sendNacosClientInfo(ClientInfo clientInfo) {
    
            HashMap<String, String> map = new HashMap<>();
            map.put("ip", clientInfo.getIp());
            map.put("port", clientInfo.getPort());
            map.put("name", clientInfo.getName());
    
            ResponseEntity<String> entity = restTemplate.postForEntity(
                    "http://" + clientInfo.getIp() + ":" + clientInfo.getPort() + "/ossa/registry",
                    map,
                    String.class
            );
    
            System.out.println(entity.getBody());
        }
    }
    

    生产者微服务

    对于这个模块的设计而言,很简单

    1. 引入手写的Nacos客户端模块/依赖
    2. 将手写的Nacos客户端模块中所需要的相关信息配置在配置文件中
      首先在生产者服务引入【手写Nacos客户端模块】
    <dependency>
        <groupId>com.ossa</groupId>
        <artifactId>ossa-spring-cloud-registry</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    

    编写application.yml文件,配置nacos信息

    client:
      info:
        ip: 127.0.0.1
        port: 8888
        name: service-producer
    

    手写Nacos服务端

    这个设计就更简单了:

    1. 接受注册信息的API接口
    2. 保存到内存中
    3. 查询接口,测试是否成功

    API接口

    @RestController
    @RequestMapping("/ossa/registry")
    public class RegistryRest {
    
        @Autowired
        private RegistryService registryService;
    
        @PostMapping
        public String registry(@RequestBody ClientInfo clientInfo) {
    
            return registryService.registry(clientInfo);
        }
    
        @GetMapping
        public ResponseEntity<Map<String, Map<String, Instance>>> getAll() {
           return ResponseEntity.ok(registryService.getAll());
        }
    }
    

    注册信息存储

    public class ServiceManager {
    
        /**
         * Map(namespace, Map(group::serviceName, Instance)).
         */
        public final static Map<String, Map<String, Instance>> serviceMap = new ConcurrentHashMap<>();
    
    }
    
    

    具体实现

    @Service
    public class RegistryServiceImpl implements RegistryService {
        @Override
        public String registry(ClientInfo clientInfo) {
            String ns = clientInfo.getNamespace();
            String group = clientInfo.getGroup();
            String name = clientInfo.getName();
            Instance instance = new Instance();
            instance.setInfo(clientInfo.getIp() + ":" + clientInfo.getPort());
            HashMap<String, Instance> map = new HashMap<>();
            map.put(group == null ? "DEFAULT_GROUP:" + name : group + ":" + name, instance);
            ServiceManager.serviceMap.put(ns == null ? "DEFAULT_NS" : ns, map);
            return "ok";
        }
    
        @Override
        public Map<String, Map<String, Instance>> getAll() {
            return ServiceManager.serviceMap;
        }
    }
    

    测试

    服务启动成功,并返回“OK”信息,说明数据发送成功。

    服务启动成功
    获取服务
    在这里插入图片描述
    举一反三,在此基础上,我们想做什么都可以了。

    那么,我们接下里,解析一下Nacos的心跳机制并手写一个Nacos的心跳机制,让大家更好的了解Nacos。奥利给!!!!

  • 相关阅读:
    ESP32与MicroPython入门-01 搭建开发环境
    oracle 12c GI卸载流程
    StartDT奇点云通过CMMI5全球软件领域最高级别成熟度认证
    python转yuyv422到jpg
    python笔记Ⅵ--函数、函数的参数
    MySQL如何改进LRU算法
    Docker Registry
    10 个高频 Python 面试题
    C语言的break、continue、switch、goto语句
    [附源码]java毕业设计校园失物招领管理系统
  • 原文地址:https://blog.csdn.net/CSDN_SAVIOR/article/details/126163813