springcloud实现自己的注册中心

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