1、springcloud 接口
Registration:主要是定义一些服务信息
类图以及方法
AbstractAutoServiceRegistration: 此抽象类很重要 监听了WebServerInitializedEvent 事件。次事件会在应用程序上下文刷新并且WebServer准备好之后发布。用于获取正在运行的服务器的本地端口
ServiceRegistry : 该接口会在AbstractAutoServiceRegistration中调用具体的实现类方法 完成注册和注销
2、pom文件依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.2.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-commons</artifactId> <version>2.2.2.RELEASE</version> </dependency> </dependencies>
3、自定义实现接口和抽象类 完成向服务端注册和注销
配置类
MyRegAutoConfiguration:完成组件注入
MyRegAutoServiceRegistration 实现AbstractAutoServiceRegistration 抽象类 实现里面的抽象方法
@Configuration //引入properties配置 @EnableConfigurationProperties(MyRegDiscoveryProperties.class) //如果spring.cloud.my.reg.discovery.enabled属性为开启状态 次配置类生效 @ConditionalOnProperty(value = "spring.cloud.my.reg.discovery.enabled", matchIfMissing = true) //在springcloud自动装配类之后 @AutoConfigureAfter({AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class}) public class MyRegAutoConfiguration { /** * @desc 实现了org.springframework.cloud.client.serviceregistry.Registration类 * 此接口主要是 定义了一些上报的信息 端口 serviceName 等 */ @Bean public MyRegistration myRegistration(MyRegDiscoveryProperties myRegDiscoveryProperties) { return new MyRegistration(myRegDiscoveryProperties); } /** * 注册的服务类 想服务端发送http请求完成注册 */ @Bean public RegService regService(RestTemplate restTemplate) { return new RegService(restTemplate); } @Bean public RestTemplate restTemplate() { return new RestTemplate(); } /** * 实现了 springcloud org.springframework.cloud.client.serviceregistry.ServiceRegistry接口 * 此类的主要作用 * 1,注册具体实现 * 2,注销具体实现 * 3,close 服务关闭 */ @Bean public MyServiceRegistry myServiceRegistry(RegService regService, MyRegDiscoveryProperties myRegDiscoveryProperties) { return new MyServiceRegistry(regService, myRegDiscoveryProperties); } @Bean public MyRegAutoServiceRegistration myRegAutoServiceRegistration(ServiceRegistry<MyRegistration> serviceRegistry, AutoServiceRegistrationProperties properties, MyRegistration myRegistration) { return new MyRegAutoServiceRegistration(serviceRegistry, properties, myRegistration); } }
/** * 此类为重要类 继承 springcloud AbstractAutoServiceRegistration 完成容器启动服务注册 */ @Configuration public class MyRegAutoServiceRegistration extends AbstractAutoServiceRegistration<MyRegistration> { private final MyRegistration myRegistration; protected MyRegAutoServiceRegistration(ServiceRegistry<MyRegistration> serviceRegistry, AutoServiceRegistrationProperties properties, MyRegistration myRegistration) { super(serviceRegistry, properties); this.myRegistration = myRegistration; } @Override protected Object getConfiguration() { return myRegistration.getMyRegDiscoveryProperties(); } @Override protected boolean isEnabled() { return myRegistration.getMyRegDiscoveryProperties().getEnabled(); } @Override protected MyRegistration getRegistration() { int i = this.getPort().get(); if (i > 0) { myRegistration.getMyRegDiscoveryProperties().setPort(i); } return this.myRegistration; } @Override protected MyRegistration getManagementRegistration() { return null; } }
注册相关类
@Data public class MyRegistration implements Registration { private final MyRegDiscoveryProperties myRegDiscoveryProperties; public MyRegistration(MyRegDiscoveryProperties myRegDiscoveryProperties) { this.myRegDiscoveryProperties = myRegDiscoveryProperties; } @Override public String getServiceId() { return myRegDiscoveryProperties.getService(); } @Override public String getHost() { URI uri= null; try { uri = new URI(myRegDiscoveryProperties.getServerAddr()); } catch (URISyntaxException e) { throw new RuntimeException(e); } return uri.getHost(); } @Override public int getPort() { return myRegDiscoveryProperties.getPort(); } @Override public boolean isSecure() { return false; } @Override public URI getUri() { URI uri= null; try { uri = new URI(myRegDiscoveryProperties.getServerAddr()); } catch (URISyntaxException e) { throw new RuntimeException(e); } return uri; } @Override public Map<String, String> getMetadata() { return null; } }
public class MyServiceRegistry implements ServiceRegistry<MyRegistration> { private final RegService regService; private final MyRegDiscoveryProperties myRegDiscoveryProperties; public MyServiceRegistry(RegService regService, MyRegDiscoveryProperties myRegDiscoveryProperties) { this.regService = regService; this.myRegDiscoveryProperties = myRegDiscoveryProperties; } @Override public void register(MyRegistration registration) { regService.registerInstance(registration.getServiceId(), registration.getMyRegDiscoveryProperties().getServerAddr(), registration.getPort()); } @Override public void deregister(MyRegistration registration) { regService.deregisterInstance(registration.getServiceId(), registration.getMyRegDiscoveryProperties().getServerAddr(), registration.getPort()); } @Override public void close() { } @Override public void setStatus(MyRegistration registration, String status) { } @Override public <T> T getStatus(MyRegistration registration) { return null; } }
注册服务类
@Slf4j public class RegService { private final ScheduledExecutorService executorService; private final RestTemplate restTemplate; public RegService(RestTemplate restTemplate) { executorService = new ScheduledThreadPoolExecutor(4, new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); thread.setDaemon(true); thread.setName("com.reg.client"); return thread; } }); this.restTemplate = restTemplate; } public void registerInstance(String serviceName, String serverAddr, int port) { String invoke = serverAddr + "/reg" + "/" + serviceName + "/" + port; RegTask regTask = new RegTask(restTemplate, invoke); executorService.scheduleAtFixedRate(regTask, 0, 5, TimeUnit.SECONDS); } public void deregisterInstance(String serviceName, String serverAddr, int port) { String invokeUrl = serverAddr + "/deregister" + "/" + serviceName + "/" + port; String forObject = restTemplate.getForObject(invokeUrl, String.class); log.info("注销 serviceName:{} result:{}", serviceName, forObject); } @AllArgsConstructor static class RegTask implements Runnable { private RestTemplate restTemplate; private String invokeUrl; @Override public void run() { try { String forObject = restTemplate.getForObject(invokeUrl, String.class); log.info("service return msg:{}", forObject); } catch (Exception e) { log.error("service invoke error msg:", e); } } } }
Properties
@Data @ConfigurationProperties("spring.cloud.myreg.discovery") public class MyRegDiscoveryProperties { /** * 服务端地址 */ private String serverAddr; /** * 服务名称 */ @Value("${spring.cloud.nacos.discovery.service:${spring.application.name:}}") private String service; /** * 是否开启自动注册 */ private Boolean enabled = true; /** * 端口 */ private int port; }
spring.factories 文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration= org.example.client.configuration.MyRegAutoConfiguration
4、服务端具体接口
1,依赖引入 就springboot web,lombok,其他没有
2,服务端较为简单,正常应该有定时任务 线程去检测 服务是否注册超时,服务是否可以剔除
@RestController public class RegController { private final Map<String, HashSet<String>> map = new ConcurrentHashMap<>(); @RequestMapping("/query") public Map<String, HashSet<String>> query() { return map; } @RequestMapping("/reg/{serviceId}/{port}") public String reg(HttpServletRequest request, @PathVariable("serviceId") String serviceId, @PathVariable("port") Integer port) { HashSet<String> orDefault = map.getOrDefault(serviceId, new HashSet<>()); orDefault.add(NetUtils.getIpAddress(request) + ":" + port); map.put(serviceId, orDefault); return "pong"; } @RequestMapping("/deregister/{serviceId}/{port}") public String deregister(HttpServletRequest request, @PathVariable("serviceId") String serviceId, @PathVariable("port") Integer port) { if (map.containsKey(serviceId)) { HashSet<String> strings = map.get(serviceId); strings.remove(NetUtils.getIpAddress(request) + ":" + port); if (strings.size() == 0) { map.remove(serviceId); } else { map.put(serviceId, strings); } } return "注销成功"; } }
5、代码地址 gitee
客户端 starter: https://gitee.com/wang_1009654487/my-reg-client
服务端 service: https://gitee.com/wang_1009654487/my-reg-service