Spring cloud系列一 包含所有基本要素的完整Spring Cloud demo

来源:互联网 发布:海淘族信用数据脸谱 编辑:程序博客网 时间:2024/06/16 12:25

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-center
application.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-devsimple.config.age=112#注册服务的zoneregistercenter.eureka.defaultzone=http://localhost:8761/eureka/

cloud-config-test.properties:

simple.config.name=git-testsimple.config.age=1#注册服务的zoneregistercenter.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_devsimple.config.age=113# 注册服务的zoneregistercenter.eureka.defaultzone=http://localhost:8761/eureka/

cloud-config-test.properties

simple.config.name=native_testsimple.config.age=1# 注册服务的zoneregistercenter.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@EnableEurekaServerpublic 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

# portserver.port=8082# 配置服务器的地址spring.cloud.config.uri=http://127.0.0.1:8888# 配置远程服务上文件名称spring.cloud.config.name=cloud-configspring.cloud.config.profile=${config.profile:dev}# 服务器注册服务器的zoneeureka.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:带多个参数请求
@Servicepublic 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.properties

server.port=8701# 配置服务器的地址spring.cloud.config.uri=http://127.0.0.1:8888spring.cloud.config.name=cloud-config# 配置远程服务上文件名称spring.cloud.config.profile=${config.profile:dev}# 服务器注册服务器的zoneeureka.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)做为执行的结果
@Componentpublic 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方式测试调用

@RestControllerpublic 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. 应用入口

SimpleCloudConsumerApplication

SpringBootApplicaSimpleCtltion@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

原创粉丝点击