【手写Nacos系列】上厕所的功夫,带你手写一个注册中心的服务注册功能
文章目录手写Nacos客户端生产者微服务手写Nacos服务端测试上一篇文章《Nacos是如何实现服务注册功能的》,我们全面解析了Nacos是如何实现服务注册的,那么这篇文章,我们就来手写一个Nacos,完成注册中心的服务注册功能。源码在文末为了更加贴近Nacos,我们本次总共开发三个模块。模拟Nacos客户端【接入微服务】模拟Nacos服务端生产者微服务【为了测试】手写Nacos客户端对于这个模块
·
上一篇文章 《Nacos是如何实现服务注册功能的》,我们全面解析了Nacos是如何实现服务注册的,那么这篇文章,我们就来手写一个Nacos,完成注册中心的服务注册功能。
源码在文末
为了更加贴近Nacos,我们本次总共开发三个模块。
- 模拟Nacos客户端【接入微服务】
- 模拟Nacos服务端
- 生产者微服务【为了测试】
手写Nacos客户端
对于这个模块的设计,主要有几下几点:
- 编写
/META-INF/spring.factories文件
加入自动装配类 - 将需要的类注入IOC容器
- 发布服务注册事件
- 监听发布的事件,准备向服务端发送数据
接下来,看具体实现
第一步,编写自动装配类
@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());
}
}
生产者微服务
对于这个模块的设计而言,很简单
- 引入手写的Nacos客户端模块/依赖
- 将手写的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服务端
这个设计就更简单了:
- 接受注册信息的API接口
- 保存到内存中
- 查询接口,测试是否成功
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。奥利给!!!!
更多推荐
已为社区贡献1条内容
所有评论(0)