From a7ec79e936c7f66b391871da0c031000fcdff6fb Mon Sep 17 00:00:00 2001 From: DerekYRC <15521077528@163.com> Date: Fri, 1 Apr 2022 20:31:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=8F=91=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.md | 180 +++++++++++++++++- .../pom.xml | 36 ++++ .../cloud/examples/ConsumerApplication.java | 48 +++++ .../src/main/resources/application.yml | 8 + .../cloud/tutu/TutuServiceInstance.java | 85 +++++++++ .../TutuDiscoveryAutoConfiguration.java | 25 +++ .../tutu/discovery/TutuDiscoveryClient.java | 62 ++++++ .../main/resources/META-INF/spring.factories | 3 +- pom.xml | 1 + 9 files changed, 443 insertions(+), 5 deletions(-) create mode 100644 mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/pom.xml create mode 100644 mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/src/main/java/com/github/cloud/examples/ConsumerApplication.java create mode 100644 mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/src/main/resources/application.yml create mode 100644 mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/TutuServiceInstance.java create mode 100644 mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/discovery/TutuDiscoveryAutoConfiguration.java create mode 100644 mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/discovery/TutuDiscoveryClient.java diff --git a/changelog.md b/changelog.md index 13db07f..90ee020 100644 --- a/changelog.md +++ b/changelog.md @@ -4,13 +4,13 @@ - spring,推荐本人写的简化版的spring框架 [**mini-spring**](https://github.com/DerekYRC/mini-spring/blob/main/README_CN.md) 。熟悉spring源码,阅读springboot源码会非常轻松。 - springboot,重点掌握:1、启动流程 2、**自动装配的原理! 自动装配的原理!! 自动装配的原理!!!** 推荐文章: - - [Spring Boot精髓:启动流程源码分析](https://www.cnblogs.com/java-chen-hao/p/11829344.html) - - [细说SpringBoot的自动装配原理](https://blog.csdn.net/qq_38526573/article/details/107084943) - - [Spring Boot 自动装配原理](https://www.cnblogs.com/javaguide/p/springboot-auto-config.html) + - [《Spring Boot精髓:启动流程源码分析》](https://www.cnblogs.com/java-chen-hao/p/11829344.html) + - [《细说SpringBoot的自动装配原理》](https://blog.csdn.net/qq_38526573/article/details/107084943) + - [《Spring Boot 自动装配原理》](https://www.cnblogs.com/javaguide/p/springboot-auto-config.html) 关于spring cloud。spring cloud是构建通用模式的分布式系统的工具集,通过[**spring-cloud-commons**](https://github.com/spring-cloud/spring-cloud-commons) 定义了统一的抽象API,相当于定义了一套协议标准,具体的实现需要符合这套协议标准。spring cloud官方整合第三方组件Eureka、Ribbon、Hystrix等实现了spring-cloud-netflix,阿里巴巴结合自身的Nacos、Sentinel等实现了spring-cloud-alibaba。本项目基于spring-cloud-commons的协议标准自主开发或整合第三方组件提供具体的实现。 -写作本项目的目的之一是降低阅读原始spring cloud源码的难度。希望掌握本项目讲解的内容之后再阅读原始spring-cloud的源码能起到事半功倍的效果,所以本项目的功能实现逻辑及原理和官方保持一致但追求代码最大精简化。 +写作本项目的目的之一是降低阅读原始spring cloud源码的难度。希望掌握本项目讲解的内容之后再阅读原始spring-cloud的源码能起到事半功倍的效果,所以本项目的功能实现逻辑及原理和官方保持一致但追求代码最大精简化,可以理解为一个源码导读的项目。 技术能力有限且文采不佳,大家可以在此[**issue**](https://github.com/DerekYRC/mini-spring-cloud/issues/1) 留言提问题和发表建议,也欢迎Pull Request完善此项目。 @@ -335,4 +335,176 @@ server: } ] ``` + +# [服务发现](#服务发现) +> 分支: service-discovery + +spring-cloud-commons定义的服务发现接口```org.springframework.cloud.client.discovery.DiscoveryClient```: +```java +public interface DiscoveryClient extends Ordered { + + /** + * Gets all ServiceInstances associated with a particular serviceId. + * @param serviceId The serviceId to query. + * @return A List of ServiceInstance. + */ + List getInstances(String serviceId); + + /** + * @return All known service IDs. + */ + List getServices(); +} +``` + +仅需实现DiscoveryClient接口即可,实现类: +```java +/** + * 服务发现实现类 + */ +public class TutuDiscoveryClient implements DiscoveryClient { + private static final Logger logger = LoggerFactory.getLogger(TutuDiscoveryClient.class); + + private TutuDiscoveryProperties tutuDiscoveryProperties; + + public TutuDiscoveryClient(TutuDiscoveryProperties tutuDiscoveryProperties) { + this.tutuDiscoveryProperties = tutuDiscoveryProperties; + } + + @Override + public List getInstances(String serviceId) { + Map param = new HashMap<>(); + param.put("serviceName", serviceId); + + String response = HttpUtil.get(tutuDiscoveryProperties.getServerAddr() + "/list", param); + logger.info("query service instance, serviceId: {}, response: {}", serviceId, response); + return JSON.parseArray(response).stream().map(hostInfo -> { + TutuServiceInstance serviceInstance = new TutuServiceInstance(); + serviceInstance.setServiceId(serviceId); + String ip = ((JSONObject) hostInfo).getString("ip"); + Integer port = ((JSONObject) hostInfo).getInteger("port"); + serviceInstance.setHost(ip); + serviceInstance.setPort(port); + return serviceInstance; + }).collect(Collectors.toList()); + } + + @Override + public List getServices() { + String response = HttpUtil.post(tutuDiscoveryProperties.getServerAddr() + "/listServiceNames", new HashMap<>()); + logger.info("query service instance list, response: {}", response); + return JSON.parseArray(response, String.class); + } +} +``` + +自动装配TutuDiscoveryAutoConfiguration: +```java +@Configuration +public class TutuDiscoveryAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public TutuDiscoveryProperties tutuDiscoveryProperties() { + return new TutuDiscoveryProperties(); + } + + @Bean + public DiscoveryClient tutuDiscoveryClient(TutuDiscoveryProperties tutuDiscoveryProperties) { + return new TutuDiscoveryClient(tutuDiscoveryProperties); + } +} +``` +spring.factories: +```yaml +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.github.cloud.tutu.registry.TutuServiceRegistryAutoConfiguration,\ + com.github.cloud.tutu.discovery.TutuDiscoveryAutoConfiguration +``` + +测试: + +1、maven install,启动服务注册和发现中心TutuServerApplication,启动服务提供者ProviderApplication,启动服务消费者ConsumerApplication(后续测试步骤均同此,不再提及) + +服务消费者代码如下: +```java +@SpringBootApplication +public class ConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(ConsumerApplication.class, args); + } + + @RestController + static class HelloController { + + @Autowired + private DiscoveryClient discoveryClient; + + private RestTemplate restTemplate = new RestTemplate(); + + @GetMapping("/hello") + public String hello() { + List serviceInstances = discoveryClient.getInstances("provider-application"); + if (serviceInstances.size() > 0) { + ServiceInstance serviceInstance = serviceInstances.get(0); + URI uri = serviceInstance.getUri(); + String response = restTemplate.postForObject(uri.toString() + "/echo", null, String.class); + return response; + } + + throw new RuntimeException("No service instance for provider-application found"); + } + } +} +``` +application.yml: +```yaml +spring: + application: + name: consumer-application + cloud: + tutu: + discovery: + server-addr: localhost:6688 + service: ${spring.application.name} +``` + +2、访问http://localhost:8080/hello ,相应报文如下: +```yaml +Port of the service provider: 19922 +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/pom.xml b/mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/pom.xml new file mode 100644 index 0000000..5966ed5 --- /dev/null +++ b/mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/pom.xml @@ -0,0 +1,36 @@ + + + + mini-spring-cloud + com.github + 1.0.0-SNAPSHOT + ../../pom.xml + + 4.0.0 + + mini-spring-cloud-consumer-examples + + + + org.springframework.boot + spring-boot-starter-web + + + + com.github + mini-spring-cloud-tutu-discovery + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/src/main/java/com/github/cloud/examples/ConsumerApplication.java b/mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/src/main/java/com/github/cloud/examples/ConsumerApplication.java new file mode 100644 index 0000000..9ded90b --- /dev/null +++ b/mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/src/main/java/com/github/cloud/examples/ConsumerApplication.java @@ -0,0 +1,48 @@ +package com.github.cloud.examples; + +import com.github.cloud.tutu.discovery.TutuDiscoveryClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import java.net.URI; +import java.util.List; + +/** + * @author derek(易仁川) + * @date 2022/3/20 + */ +@SpringBootApplication +public class ConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(ConsumerApplication.class, args); + } + + @RestController + static class HelloController { + + @Autowired + private TutuDiscoveryClient discoveryClient; + + private RestTemplate restTemplate = new RestTemplate(); + + @GetMapping("/hello") + public String hello() { + List serviceInstances = discoveryClient.getInstances("provider-application"); + if (serviceInstances.size() > 0) { + ServiceInstance serviceInstance = serviceInstances.get(0); + URI uri = serviceInstance.getUri(); + String response = restTemplate.postForObject(uri.toString() + "/echo", null, String.class); + return response; + } + + throw new RuntimeException("No service instance for provider-application found"); + } + } +} + diff --git a/mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/src/main/resources/application.yml b/mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/src/main/resources/application.yml new file mode 100644 index 0000000..e1b83ea --- /dev/null +++ b/mini-spring-cloud-examples/mini-spring-cloud-consumer-examples/src/main/resources/application.yml @@ -0,0 +1,8 @@ +spring: + application: + name: consumer-application + cloud: + tutu: + discovery: + server-addr: localhost:6688 + service: ${spring.application.name} \ No newline at end of file diff --git a/mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/TutuServiceInstance.java b/mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/TutuServiceInstance.java new file mode 100644 index 0000000..2d66d0c --- /dev/null +++ b/mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/TutuServiceInstance.java @@ -0,0 +1,85 @@ +package com.github.cloud.tutu; + +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.ServiceInstance; + +import java.net.URI; +import java.util.Map; + +/** + * 服务实例 + * + * @author derek(易仁川) + * @date 2022/3/20 + */ +public class TutuServiceInstance implements ServiceInstance { + + private String serviceId; + + private String host; + + private int port; + + private boolean secure = false; + + private Map metadata; + + public TutuServiceInstance() { + } + + public TutuServiceInstance(String serviceId, String host, int port) { + this.serviceId = serviceId; + this.host = host; + this.port = port; + } + + @Override + public String getServiceId() { + return serviceId; + } + + @Override + public String getHost() { + return host; + } + + @Override + public int getPort() { + return port; + } + + @Override + public boolean isSecure() { + return secure; + } + + @Override + public URI getUri() { + return DefaultServiceInstance.getUri(this); + } + + @Override + public Map getMetadata() { + return metadata; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public void setHost(String host) { + this.host = host; + } + + public void setPort(int port) { + this.port = port; + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } +} diff --git a/mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/discovery/TutuDiscoveryAutoConfiguration.java b/mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/discovery/TutuDiscoveryAutoConfiguration.java new file mode 100644 index 0000000..f076fbf --- /dev/null +++ b/mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/discovery/TutuDiscoveryAutoConfiguration.java @@ -0,0 +1,25 @@ +package com.github.cloud.tutu.discovery; + +import com.github.cloud.tutu.TutuDiscoveryProperties; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author derek(易仁川) + * @date 2022/3/20 + */ +@Configuration +public class TutuDiscoveryAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public TutuDiscoveryProperties tutuDiscoveryProperties() { + return new TutuDiscoveryProperties(); + } + + @Bean + public TutuDiscoveryClient tutuDiscoveryClient(TutuDiscoveryProperties tutuDiscoveryProperties) { + return new TutuDiscoveryClient(tutuDiscoveryProperties); + } +} diff --git a/mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/discovery/TutuDiscoveryClient.java b/mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/discovery/TutuDiscoveryClient.java new file mode 100644 index 0000000..4ac0b91 --- /dev/null +++ b/mini-spring-cloud-tutu-discovery/src/main/java/com/github/cloud/tutu/discovery/TutuDiscoveryClient.java @@ -0,0 +1,62 @@ +package com.github.cloud.tutu.discovery; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.cloud.tutu.TutuDiscoveryProperties; +import com.github.cloud.tutu.TutuServiceInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 服务发现实现类 + * + * @author derek(易仁川) + * @date 2022/3/20 + */ +public class TutuDiscoveryClient implements DiscoveryClient { + private static final Logger logger = LoggerFactory.getLogger(TutuDiscoveryClient.class); + + private TutuDiscoveryProperties tutuDiscoveryProperties; + + public TutuDiscoveryClient(TutuDiscoveryProperties tutuDiscoveryProperties) { + this.tutuDiscoveryProperties = tutuDiscoveryProperties; + } + + @Override + public List getInstances(String serviceId) { + Map param = new HashMap<>(); + param.put("serviceName", serviceId); + + String response = HttpUtil.get(tutuDiscoveryProperties.getServerAddr() + "/list", param); + logger.info("query service instance, serviceId: {}, response: {}", serviceId, response); + return JSON.parseArray(response).stream().map(hostInfo -> { + TutuServiceInstance serviceInstance = new TutuServiceInstance(); + serviceInstance.setServiceId(serviceId); + String ip = ((JSONObject) hostInfo).getString("ip"); + Integer port = ((JSONObject) hostInfo).getInteger("port"); + serviceInstance.setHost(ip); + serviceInstance.setPort(port); + return serviceInstance; + }).collect(Collectors.toList()); + } + + @Override + public List getServices() { + String response = HttpUtil.post(tutuDiscoveryProperties.getServerAddr() + "/listServiceNames", new HashMap<>()); + logger.info("query service instance list, response: {}", response); + return JSON.parseArray(response, String.class); + } + + @Override + public String description() { + return "Spring Cloud Tutu Discovery Client"; + } +} diff --git a/mini-spring-cloud-tutu-discovery/src/main/resources/META-INF/spring.factories b/mini-spring-cloud-tutu-discovery/src/main/resources/META-INF/spring.factories index 50f8c9d..e40fa51 100644 --- a/mini-spring-cloud-tutu-discovery/src/main/resources/META-INF/spring.factories +++ b/mini-spring-cloud-tutu-discovery/src/main/resources/META-INF/spring.factories @@ -1,2 +1,3 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - com.github.cloud.tutu.registry.TutuServiceRegistryAutoConfiguration \ No newline at end of file + com.github.cloud.tutu.registry.TutuServiceRegistryAutoConfiguration,\ + com.github.cloud.tutu.discovery.TutuDiscoveryAutoConfiguration \ No newline at end of file diff --git a/pom.xml b/pom.xml index a73dbd2..883297c 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,7 @@ mini-spring-cloud-examples/tutu-server mini-spring-cloud-tutu-discovery mini-spring-cloud-examples/mini-spring-cloud-provider-example + mini-spring-cloud-examples/mini-spring-cloud-consumer-examples