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


    http://www.spring4all.com/article/746

    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部分。

    1. 父工程

    工程: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. 配置中心
    3. 配置中心

    工程名称: cloud-config-center
    配置中心的配置文件方式有git,本地文件(native),svn,这里只演示前2者的使用方式。

    3.1. 配置文件使用git方式

    工程名称: cloud-config-center
    application.properties

    server.port=8888
    1
    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
    1
    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);
    }
    
    1. 服务提供者

    工程名称: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.properties

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

    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);
    }
    
    1. 测试

    按照如下顺序启动服务: 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

  • 相关阅读:
    BZOJ3105:[CQOI2013]新Nim游戏(线性基,贪心)
    BZOJ5102:[POI2018]Prawnicy(贪心,堆)
    BZOJ3533:[SDOI2014]向量集(线段树,三分,凸包)
    BZOJ3569:DZY Loves Chinese II(线性基)
    BZOJ3534:[SDOI2014]重建(矩阵树定理)
    【BZOJ 1202】 [HNOI2005]狡猾的商人
    【BZOJ 1003】 [ZJOI2006]物流运输trans
    【BZOJ 2321】 [BeiJing2011集训]星器
    【BZOJ 1010】 [HNOI2008]玩具装箱toy
    【BZOJ 2730】 [HNOI2012]矿场搭建
  • 原文地址:https://www.cnblogs.com/sharpest/p/13678502.html
Copyright © 2020-2023  润新知