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