[置顶] Spring cloud系列一 包含所有基本要素的完整Spring Cloud demo
2017-08-27 22:27
826 查看
1. 概述
本文实现了包含spring cloud的所有的基本要素的完整demo。配置中心、服务注册和发现中心、通过eureka实现服务的注册和发现、通过feign+hystrix调用服务。1.1 Demo概述
下图配置中心:通过git/svn/本地中获取公共配置文件,并通过REST方式供其它服务获取配置信息
服务注册中心:提供服务注册和发现
服务群(服务提供者):提供服务。服务启动时,从配置中心获取公共配置信息,并将本服务通过eureka注册到注册中心。在注册时,需要配置本服务的名称,调用者通过此名称调用此服务
客户端(服务调用者):客户端启动时,从配置中心获取公共配置信息,通过要访问的服务注册到服务注册中心的名称调用对应的服务。如果服务注册的方式是eureka,则客户端也需要使用eureka访问。通过ribbon可以实现对服务群的均衡负载。hystrix作为断路器。feign方式简化了服务的调用方式。
服务路由:通过zuul实现服务的路由。 zuul的作用类似Nginx,这个模块在spring cloud不是必须的。
下文介绍如何通过spring cloud实现如上的一个简单的demo,不含zuul部分。
3. 父工程
工程:cloud-parent在pom.xml中定义所有服务的公共依赖jar
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <!-- 使用spring cloud必须引入 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- logback + slf4j --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> </dependency> <!-- 测试模块,包括JUnit、Hamcrest、Mockito --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.37</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId> spring-boot-configuration-processor </artifactId> </dependency> </dependencies>
3. 配置中心
工程名称: cloud-config-center配置中心的配置文件方式有git,本地文件(native),svn,这里只演示前2者的使用方式。
3.1. 配置文件使用git方式
工程名称: cloud-config-centerapplication.properties
server.port=8888
application-gitsimple.properties
# 指定配置文件所在的git工程路径 spring.cloud.config.server.git.uri=https://github.com/hryou0922/spring_cloud.git # 表示将搜索该文件夹下的配置文件 spring.cloud.config.server.git.searchPaths=cloud-config-git/simple
CloudGitConfigServerApplication
@EnableConfigServer :激活该应用为配置文件服务器:读取远程配置文件,转换为rest接口服务
@SpringBootApplication @EnableConfigServer // 激活该应用为配置文件服务器:读取远程配置文件,转换为rest接口服务 public class CloudGitConfigServerApplication { public static void main(String[] args) { args = new String[1]; args[0] = "--spring.profiles.active=gitsimple"; SpringApplication.run(CloudGitConfigServerApplication.class, args); } }
运行CloudGitConfigServerApplication即可启动服务
Git的配置文件放置在这个工程中:cloud-config-git
在simple有两个文件,名称和内容如下:
cloud-config-dev.properties:
simple.config.name=git-dev simple.config.age=112 #注册服务的zone registercenter.eureka.defaultzone=http://localhost:8761/eureka/
cloud-config-test.properties:
simple.config.name=git-test simple.config.age=1 #注册服务的zone registercenter.eureka.defaultzone=http://localhost:8761/eureka/
simple.config.name和simple.config.age做为测试数据,用于后续服务和客户读取配置。
registercenter.eureka.defaultzone:服务注册到服务注册的zone
3.2 配置方式使用native方式
工程名称: cloud-config-center在resoucres的目录下config/simple的创建配置文件
cloud-config-dev.properties
simple.config.name=native_dev simple.config.age=113 # 注册服务的zone registercenter.eureka.defaultzone=http://localhost:8761/eureka/
cloud-config-test.properties
simple.config.name=native_test simple.config.age=1 # 注册服务的zone registercenter.eureka.defaultzone=http://localhost:8761/eureka/
application-nativesimple.properties
server.port=8888 # native:启动从本地读取配置文件,必须指定active的值,才可以使用本场配置模式 spring.profiles.active=native # 自定义配置文件路径 spring.cloud.config.server.native.searchLocations=classpath:/config/simple/
CloudNativeConfigServerApplication
@SpringBootApplication @EnableConfigServer // 激活该应用为配置文件服务器:读取远程配置文件,转换为rest接口服务 public class CloudNativeConfigServerApplication { public static void main(String[] args) { args = new String[1]; // 使用native不可以使用spring.profiles.active的方式使用native模式 // args[0] = "--spring.profiles.active=nativesimple"; args[0] = "--spring.config.name=application-nativesimple"; SpringApplication.run(CloudNativeConfigServerApplication.class, args); } }
运行CloudGitConfigServerApplication即可启动服务
4. 注册中心
工程名称:cloud-registration-center提供服务的注册和发现
4.1 pom.xml
pom.xml除了继承cloud-parent的父pom.xml外,还需要加上如下依赖jar<dependencies> <!-- eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> </dependencies>
4.2 application.properties
应用启动配置application.properties
server.port=8761
application-simple.properties
# eureka : 主要配置属性在EurekaInstanceConfigBean和EurekaClientConfigBean中 eureka.instance.hostname=127.0.0.1 #eureka.client.enabled=false # 表示是否注册自身到eureka服务器,因为当前这个应用就是eureka服务器,没必要注册自身 eureka.client.registerWithEureka=false # 表示是否从eureka服务器获取注册信息 eureka.client.fetchRegistry=false # 设置eureka服务器所在的地址,查询服务和注册服务都需要依赖这个地址 eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
4.3 应用入口
SimpleCloudRegistrationCenterApplication@EnableEurekaServer:启动Eureka
@SpringBootApplication @EnableEurekaServer public class SimpleCloudRegistrationCenterApplication { public static void main(String[] args) { args = new String[1]; args[0] = "--spring.profiles.active=simple"; SpringApplication.run(SimpleCloudRegistrationCenterApplication.class, args); } }
5. 服务提供者
工程名称:cloud-service实现一个简单服务,并注册到注册中心
5.1. pom.xml
pom.xml除了继承cloud-parent的父pom.xml外,还需要加上如下依赖jar<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-client</artifactId> </dependency> <!-- eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-eureka-client</artifactId> </dependency> </dependencies>
5.2 application.properties ###
application.properties# port server.port=8082 # 配置服务器的地址 spring.cloud.config.uri=http://127.0.0.1:8888 # 配置远程服务上文件名称 spring.cloud.config.name=cloud-config spring.cloud.config.profile=${config.profile:dev} # 服务器注册服务器的zone eureka.client.serviceUrl.defaultZone=${registercenter.eureka.defaultzone}
application-simple.properties
# 本服务注册到注册到服务器的名称, 这个名称就是后面调用服务时的服务标识符 spring.application.name=cloud-simple-service
5.3. SimpleConfig
如果应用启动链接到远程配置中心,则应用会自动从配置中心获取对应的数据,并将数据填充到本对象中@Configuration @ConfigurationProperties(prefix = "simple.config" ,ignoreUnknownFields = false) public class SimpleConfig { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString(){ return "name="+name+" | age=" + age; } }
5.4. SimpleService
服务提供类,提供3种方式的调用:simple:无参请求
simpleWithOneParam:带单个参数请求
simpleWithQry:带多个参数请求
@Service public class SimpleService { @Autowired private SimpleConfig simpleConfig; // public SimpleDto simple(){ SimpleDto simpleDto = new SimpleDto(); simpleDto.setAge(simpleConfig.getAge()); simpleDto.setName(simpleConfig.getName()); simpleDto.setRandomNum(new Random().nextInt(1000)); return simpleDto; } public SimpleDto simpleWithOneParam(String transparentString){ SimpleDto simpleDto = new SimpleDto(); simpleDto.setAge(simpleConfig.getAge()); simpleDto.setName(simpleConfig.getName()); simpleDto.setRandomNum(new Random().nextInt(1000)); simpleDto.setTransparentString(transparentString); return simpleDto; } public SimpleDto simpleWithQry(SimpleQry qry){ SimpleDto simpleDto = new SimpleDto(); simpleDto.setAge(simpleConfig.getAge()); simpleDto.setName(simpleConfig.getName()); simpleDto.setRandomNum(qry.getRandomNum()); simpleDto.setTransparentString(qry.getTransparentString()); return simpleDto; } }
5.5. SimpleController
controller层提供真正的对外REST服务@RestController public class SimpleController { @Autowired private SimpleService simpleService; /** * 无参服务 * @return */ @RequestMapping(value = "/simple") public SimpleDto simple() { return simpleService.simple(); } /** * 单个参数请求 * @param transparentString * @return */ @RequestMapping(value = "/simplewithoneparam/{transparentString}") public SimpleDto simpleWithOneParam(@PathVariable("transparentString")String transparentString) { return simpleService.simpleWithOneParam(transparentString); } /** * 带多个参数请求 * @param qry * @return */ @RequestMapping(value = "/simplewithqry") public SimpleDto simpleWithQry(@RequestBody SimpleQry qry) { return simpleService.simpleWithQry(qry); } }
5.6. 应用入口
SimpleCloudServiceApplication:@EnableDiscoveryClient: 通过eureka注册服务到注册中心
fastJsonHttpMessageConverters():本文使用fastjson做为rest通信中的json解析器
@SpringBootApplication @EnableDiscoveryClient // 通过eureka注册服务注册中 public class SimpleCloudServiceApplication { public static void main(String[] args) { // 如果读取远程服务器上读取配置文件,如果执行成功,会有如下打印信息: // Located property source: CompositePropertySource // [name='configService', propertySources=[MapPropertySource // [name='https://github.com/hryou0922/spring_cloud.git/cloudconfig/cloud-config-dev.properties']]] args = new String[1]; args[0] = "--spring.profiles.active=simple"; SpringApplication.run(SimpleCloudServiceApplication.class, args); } /** * 使用fastjson做为json的解析器 * @return */ @Bean public HttpMessageConverters fastJsonHttpMessageConverters() { FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); FastJsonConfig fastJsonConfig = new FastJsonConfig(); // fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat); fastConverter.setFastJsonConfig(fastJsonConfig); HttpMessageConverter<?> converter = fastConverter; return new HttpMessageConverters(converter); } }
6. 客户端(服务调用者)
工程名称:cloud-consumer服务的调用者,从配置中心下载公共配置,通过feign调用服务,并通过hystrix配置断路器
6.1 pom.xml
pom.xml除了继承cloud-parent的父pom.xml外,还需要加上如下依赖jar<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-client</artifactId> </dependency> <!-- feign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> </dependencies>
6.2. application.properties
application.propertiesserver.port=8701 # 配置服务器的地址 spring.cloud.config.uri=http://127.0.0.1:8888 spring.cloud.config.name=cloud-config # 配置远程服务上文件名称 spring.cloud.config.profile=${config.profile:dev} # 服务器注册服务器的zone eureka.client.serviceUrl.defaultZone=${registercenter.eureka.defaultzone}
application-simple.properties
在我使用的这个版本,默认不开启hystrix,需要我们自己启动断路器
server.port=8701 # 启动hystrix,通过HystrixFeignConfiguration查看配置,hystrix默认不启动 feign.hystrix.enabled=true # 要访问服务的名称 feign.servicename=cloud-simple-service # 本服务注册到注册服务器时的名称 spring.application.name=simple_consumer
6.3. @FeignClient式服务调用ISimpleClient
定义访问服务的接口ISimpleClient使用@FeignClien注解接口,name指定要访问服务的名称,fallback 设置断路器
feign默认已经使用ribbion做为负载均衡:详细配置见 FeignRibbonClientAutoConfiguration
这时演示提供3种情况的服务调用,分别对应服务提供者3种情况
- call:无参请求
- simpleWithOneParam:带单个参数请求
- simpleWithQry:带多个参数请求
SimpleQry , SimpleDto 是POJO类,这里略,自己看源代码
/** * 通过feign访问服务, * name:指定服务的名称 * fallback:指定断路器 * * feign默认已经使用ribbion做为负载均衡:详细配置见 FeignRibbonClientAutoConfiguration * * @author Administrator * */ @FeignClient(name="${feign.servicename}", fallback = FeignClientFallback.class) public interface ISimpleClient { @RequestMapping(method = RequestMethod.GET, value = "/simple") String call(); @RequestMapping(value = "/simplewithoneparam/{transparentString}") SimpleDto simpleWithOneParam(@PathVariable("transparentString") String transparentString); // 如果使用fastjson,则需要加上consumes参数 @RequestMapping(value = "/simplewithqry", method = RequestMethod.POST, consumes="application/json; charset=UTF-8") SimpleDto simpleWithQry(@RequestBody SimpleQry qry); }
6.4. 断路器 FeignClientFallback
实现ISimpleClient如果ISimpleClient 配置了断路器,那么程序在调用远程服务方法(如call)失败时,会调用此类的对应方法(如call)做为执行的结果
@Component public class FeignClientFallback implements ISimpleClient { @Override public String call() { System.out.println(this); return "access remote server error!"; } @Override public SimpleDto simpleWithOneParam(String transparentString) { SimpleDto dto = new SimpleDto(); dto.setCode(-1); dto.setErrorMsg("access remote server error!"); return dto; } @Override public SimpleDto simpleWithQry(SimpleQry qry) { SimpleDto dto = new SimpleDto(); dto.setCode(-1); dto.setErrorMsg("access remote server error!"); return dto; } }
6.5. SimpleCtl
controller层,提供rest方式测试调用@RestController public class SimpleCtl { @Autowired private ISimpleClient feignClient; @RequestMapping(value="/feign-client-call") public String simpleClientCall(){ return feignClient.call(); } @RequestMapping(value="/feign-client-call/{transparentString}") public SimpleDto simpleWithOneParam(@PathVariable("transparentString") String transparentString){ return feignClient.simpleWithOneParam(transparentString); } @RequestMapping(value="/feign-client-call-with-qry") public SimpleDto simpleWithQry(){ SimpleQry qry = new SimpleQry(); qry.setRandomNum(123456); qry.setTransparentString("transparentString"); return feignClient.simpleWithQry(qry); } }
6.6. 应用入口
SimpleCloudConsumerApplicationSpringBootApplicaSimpleCtltion @EnableEurekaClient // 配置本应用将使用服务注册和服务发现 // @EnableHystrix // 启用断路器,断路器依赖于服务注册和发现。 @EnableFeignClients // 启用feign REST访问 public class SimpleCloudConsumerApplication { public static void main(String[] args) { args = new String[1]; args[0] = "--spring.profiles.active=simple"; SpringApplication.run(SimpleCloudConsumerApplication.class, args); } /** * 使用fastjson做为json的解析器 * @return */ @Bean public HttpMessageConverters fastJsonHttpMessageConverters() { FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat); fastConverter.setFastJsonConfig(fastJsonConfig); HttpMessageConverter<?> converter = fastConverter; return new HttpMessageConverters(converter); } }
7. 测试
按照如下顺序启动服务: cloud-config-center (配置中心)–> cloud-registration-center(服务注册中心) –> cloud-service(服务提供者) –> cloud-consumer(服务调用者)访问如下地址,可以看到当前注册到注册中心的信息
http://127.0.0.1:8761/
测试地址,访问如下的地址,演示3种服务调用 :
无参请求:http://127.0.0.1:8701/feign-client-call
带单个参数请求:http://127.0.0.1:8701/feign-client-call/transparentString
带多个参数请求:http://127.0.0.1:8701/feign-client-call-with-qry
8. 代码
以上的详细的代码见上面github代码,请使用tag v0.1,不要使用master
相关文章推荐
- 朱晔和你聊Spring系列S1E8:凑活着用的Spring Cloud(含一个实际业务贯穿所有组件的完整例子)
- Spring cloud系列二 Spring Cloud 配置中心的基本用法
- SpringCloud系列九:SpringCloudConfig 基础配置(SpringCloudConfig 的基本概念、配置 SpringCloudConfig 服务端、抓取配置文件信息、客户端使用 SpringCloudConfig 进行配置、单仓库目录匹配、应用仓库自动选择、仓库匹配模式)
- 【微框架】之一:从零开始,轻松搞定SpringCloud微服务系列--开山篇(spring boot 小demo)
- 【微框架】之一:从零开始,轻松搞定SpringCloud微服务系列--开山篇(spring boot 小demo)
- Spring Cloud | 学习系列 Spring Cloud中基于Sleuth的参数透传功能探索
- Spring Cloud组件完整demo
- Spring cloud系列十四 分布式链路监控Spring Cloud Sleuth
- 干货实操:微服务Spring Cloud 系列(一) Spring cloud Config 用SVN做配置仓库
- Spring Cloud的基本认识和使用Spring Cloud的基本教程
- 古典小说系列合集 可点评、可标注、可编辑、可语音朗读 的有声古典小说系列 (基本包含了所有古典小说)
- [置顶] Spring Cloud_8_SpringCloud与Ribbon
- SpringCloud系列八:Zuul 路由访问(Zuul 的基本使用、Zuul 路由功能、zuul 过滤访问、Zuul 服务降级)
- [置顶] Spring Cloud Data Flow Server for Apache Mesos 适用于mesos平台的springcloud数据流服务器(DCOS构建)
- Spring 2.5 jar 所有开发包及完整文档及项目开发实例
- spring-cloud源码解析-hystrix的基本介绍和配置属性说明
- 【持续更新】SpringCloud服务注册与调用Demo
- 基本spring测试框架的测试demo
- spring cloud 学习(1) - 基本的SOA示例
- spring cloud 入门实践系列 - eureka