Spring Cloud Demo

Spring Cloud Demo

本文介绍Spring Cloud 常用的组件的demo代码。gitee代码:gitee.com/Aes_yt/spri...

包括Spring Cloud Eureka,Spring Cloud Feign,Spring Cloud Hystrix,Spring Cloud Ribbon,Spring Cloud Zuul,Spring Cloud Config,Spring Cloud Sleuth。

Spring Cloud Eureka

Server

  1. pom引入:

    xml 复制代码
    <dependency>
    	<groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
  2. 代码:

    SpringBootApplication 启动类加入 @EnableEurekaServer注解。

  3. 配置:

    yaml 复制代码
    server:
      port: 8761
    
    eureka:
      instance:
        hostname: localhost
      client:
        register-with-eureka: false
        fetch-registry: false
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      server:
        wait-time-in-ms-when-sync-empty: 0
        enable-self-preservation: false

Client

  1. pom引入:

    xml 复制代码
    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
  2. 代码:

    SpringBootApplication 启动类加入 @EnableDiscoveryClient注解。

  3. 配置:

    yaml 复制代码
    server:
      port: 8081
    
    spring:
      application:
        name: demo-client1
    
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/

TIPS. 非java语言也可使用Eureka提供的REST API接口接入Server。 wiki

常见问题

  1. 为什么服务上线了,Eureka Client 不能及时获取到。

    Eureka Server 的 REST API 有response cache,需要等缓存过期后才能更新数据。

  2. 为什么服务下线了,Eureka Server 接口返回的信息还会存在。

    应用实例异常挂掉,没有在挂掉之前告知Server 要下线。这个就需要依赖Eureka Server的EvictionTask 去剔除。

  3. 其他:

    springcloud对springboot的版本是有要求的,如果不一致,会启动不起来的。详细可以看官网的版本要求。

Spring Cloud Feign + Spring Cloud Hystrix

demo-hello

  1. 首先先创建一个 demo 的 module,接入Eureka配置(eureka-client )。设置端口8082,里面只有一个get方法,我们用postman调用 http://localhost:8082/hello/testGet?param=hello,能够正常返回。

    java 复制代码
    @RestController
    @RequestMapping("/hello")
    @Slf4j
    public class HelloController {
        @GetMapping("/testGet")
        public BaseResp<String> testGet(@RequestParam("param") String param) {
            log.info("[demo-hello] testGet:{}", param);
            return BaseResp.success(param);
        }
    }

    yml:

    yaml 复制代码
    server:
      port: 8082
    spring:
      application:
        name: demo-hello
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/

feign-client

  1. 创建一个新module。引入Eureka-client依赖,feign依赖和hystrix依赖。

    xml 复制代码
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!-- cloud 2020.0.x 之后无此依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

    注意:hystrix 在 spring-cloud 2020.0.x 版本废弃,之后的版本推荐使用 Resilience4j 进行服务的熔断。

  2. yaml 配置

    yaml 复制代码
    server:
      port: 8083
    spring:
      application:
        name: feign-client
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
    
    feign:
    #  hystrix熔断开关
      hystrix:
        enabled: true
    #  feign-client的超时时间
      client:
        config:
          default:
            connect-timeout: 3000
            read-timeout: 3000
            logger-level: basic
    
    # 设置hystrix服务降级超时时间
    hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 15000
  3. Application 注解

    @EnableFeignClients:@EnableFeignClients 是一个 Spring Cloud 注解,用于启用 Feign 客户端的功能。

    @EnableCircuitBreaker:@EnableCircuitBreaker 是 Spring Cloud 提供的一个注解,用于启用熔断器(Circuit Breaker)的功能。

    java 复制代码
    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    @EnableCircuitBreaker
    public class FeignClientApplication {
        public static void main(String[] args) {
            SpringApplication.run(FeignClientApplication.class, args);
        }
    }
  4. 建立Feign调用Service

    java 复制代码
    @FeignClient(name = "demo-hello", contextId = "feign-hello", path = "/hello", fallbackFactory = FeignHelloServiceHystrix.class)
    public interface FeignHelloService {
        @RequestMapping(value = "/testGet", method = RequestMethod.GET)
        BaseResp<String> testGet(@RequestParam("param") String param);
    }

    name = "demo-hello" 就是 demo 项目的 spring.application.name,contentxId 就相当于这个调用service的唯一id,path就是统一前缀。fallbackFactory 就是降级后的工厂。所以我们要实现这个工厂。

    我这边的逻辑,就是记录一下日志,然后返回统一的错误对象。

    java 复制代码
    @Slf4j
    @Component
    public class FeignHelloServiceHystrix implements FallbackFactory<FeignHelloService> {
        @Override
        public FeignHelloService create(Throwable cause) {
            log.error("feign调用helloController报错", cause);
            return new FeignHelloService() {
                public BaseResp<String> testGet(String param) {
                    return BaseResp.error(param);
                }
            };
        }
    }
  5. 测试一下,

    java 复制代码
        @GetMapping("/testGet")
        public BaseResp<String> testGet(@RequestParam("param") String param) {
    //        try {
    //            Thread.sleep(6000);
    //        } catch (InterruptedException e) {
    //            throw new RuntimeException(e);
    //        }
    //        if(!param.isEmpty()){
    //            throw new RuntimeException("error...");
    //        }
            log.info("[demo-hello] testGet:{}", param);
            return BaseResp.success(param);
        }

    testGet 6秒钟才响应或者直接抛出异常,都是会进入FeignHelloServiceHystrix中打印日志。

附加

  1. Feign 加日志打印

    1. xml配置Feign客户端

      yaml 复制代码
      # Feign 日志配置
      logging:
        level:
          com.yt.demo.service.feign: debug
    2. Feign 配置

      java 复制代码
      /**
       * Feign 配置
       */
      @Slf4j
      @Configuration
      public class FeignConfig {
      
          /**
           * NONE:不记录任何信息
           * BASIC:仅记录请求方法、URL以及响应状态码和执行时间.
           * HEADERS:除了记录BASIC级别的信息外,还会记录请求和响应的头信息
           * FULL:记录所有请求与响应的明细,包括头信息、请求体、元数据
           */
          @Bean
          Logger.Level feignLoggerLevel() {
              return Logger.Level.FULL;
          }
      }
    3. 效果如下:

      yaml 复制代码
      2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] ---> POST http://demo-hello/hello/testPost HTTP/1.1
      2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] Content-Length: 30
      2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] Content-Type: application/json
      2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] 
      2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] {"param":"Post method: hello"}
      2023-06-23 11:38:43.026 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] ---> END HTTP (30-byte body)
      2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] <--- HTTP/1.1 200 (2ms)
      2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] connection: keep-alive
      2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] content-type: application/json
      2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] date: Fri, 23 Jun 2023 03:38:43 GMT
      2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] keep-alive: timeout=60
      2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] transfer-encoding: chunked
      2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] 
      2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] {"code":200,"data":"Post method: hello","msg":"success"}
      2023-06-23 11:38:43.029 DEBUG 496 --- [ix-demo-hello-4] c.y.d.service.feign.FeignHelloService    : [FeignHelloService#testPost] <--- END HTTP (56-byte body)
  2. 文件上传

    1. feign Client 里面新增文件上传方法

      java 复制代码
          @RequestMapping(value = "/testFile", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE,
                  consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
          BaseResp<String> testFile(@RequestPart("file") MultipartFile file);

      注意配置@RequestPart 注解,参数加上:produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE

常见问题

  1. demo项目的方法返回报错,或者超时,都并没有进入熔断工厂。

    检查一下feign-client的hystrix是否启用: feign.hystrix.enabled: true

  2. 配置了feign-client的超时时间为3s,demo返回时间6s,但是1s就马上进入熔断工厂报超时,并没有等待3s。

    feign-client的超时时间和hystrix的超时时间都要配置。

  3. 配置了超时时间,但是还是不生效。

    根据你的cloud版本搜索一下,对应的配置怎么配。有可能不同版本的配置方法不一样,单词改变了之类的都是有可能的。

  4. feign调用报错:Load balancer does not have available server for client : xxx

    feign客户端的yaml配置加上 fetch-registry: true

    yaml 复制代码
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
        fetch-registry: true

Spring Cloud Ribbon

demo-hello

  1. demo-hello 复用上面Feign的controller新增一个测试方法,打印出当前服务器端口

    java 复制代码
        @GetMapping("/testRibbon")
        public BaseResp<String> testRibbon(@RequestParam("param") String param, HttpServletRequest httpServletRequest) {
            log.info("接收到请求,参数:{}, serverPort:{}", param, httpServletRequest.getServerPort());
            return BaseResp.success("Response from server port: " + httpServletRequest.getServerPort());
        }
  2. 启动项目,之后修改application.xml的端口号port,重新启动一个实例。

  3. 启动成功之后,在Eureka界面可以看到两个启动的实例。

    Application AMIs Availability Zones Status
    DEMO-HELLO n/a (2) (2) UP (2) - 192.168.0.101:demo-hello:8082 , 192.168.0.101:demo-hello:8084

ribbon-client

  1. 新建一个项目。[可以从Eureka-client复制,然后修改spring.application.name和pom文件的artifactId]。

  2. 引入ribbon依赖

    xml 复制代码
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
  3. 新建ribbon配置类,重点是用@LoadBalance注解来声明restTemplate具有负载均衡能力。而且这样在使用restTeamplate的时候就能通过eureka上面的服务名来调用服务了,

    java 复制代码
    @Slf4j
    @Configuration
    public class RibbonConfig {
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }
  4. 新建一个测试类,直接调用十次请求

    java 复制代码
    @RestController
    @RequestMapping("/client")
    @Slf4j
    public class HelloController {
        @Autowired
        private RestTemplate restTemplate;
    
        @GetMapping("/testRibbon")
        public BaseResp<String> testRibbon(@RequestParam("param") String param) {
            String url = "http://demo-hello/hello/testRibbon?param=" + param;
    		
            for (int i = 0; i < 10; i++) {
                BaseResp<?> resp = restTemplate.getForObject(url, BaseResp.class);
                log.info("i-{}: {}", i, resp);
            }
            return BaseResp.success(null);
        }
    }
  5. 返回结果:

    yaml 复制代码
    2023-06-23 15:42:40.802  INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController   : i-0: BaseResp(code=200, data=Response from server port: 8084, msg=success)
    2023-06-23 15:42:40.805  INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController   : i-1: BaseResp(code=200, data=Response from server port: 8082, msg=success)
    2023-06-23 15:42:40.807  INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController   : i-2: BaseResp(code=200, data=Response from server port: 8084, msg=success)
    2023-06-23 15:42:40.810  INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController   : i-3: BaseResp(code=200, data=Response from server port: 8082, msg=success)
    2023-06-23 15:42:40.812  INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController   : i-4: BaseResp(code=200, data=Response from server port: 8084, msg=success)
    2023-06-23 15:42:40.814  INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController   : i-5: BaseResp(code=200, data=Response from server port: 8082, msg=success)
    2023-06-23 15:42:40.818  INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController   : i-6: BaseResp(code=200, data=Response from server port: 8084, msg=success)
    2023-06-23 15:42:40.820  INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController   : i-7: BaseResp(code=200, data=Response from server port: 8082, msg=success)
    2023-06-23 15:42:40.824  INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController   : i-8: BaseResp(code=200, data=Response from server port: 8084, msg=success)
    2023-06-23 15:42:40.826  INFO 7916 --- [nio-8085-exec-2] com.yt.demo.controller.HelloController   : i-9: BaseResp(code=200, data=Response from server port: 8082, msg=success)

    ribbon的默认负载均衡策略是ZoneAvoidanceRule,可以看出请求分别调到了8084和8082两个服务实例上。

  6. 负载均衡策略配置

    1. Ribbon内置的负载均衡规则:

      规则名称 特点
      AvailabilityFilteringRule 过滤掉一直连接失败的被标记为circuit tripped的后端Server,并 过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate 来包含过滤server的逻辑,其实就是检查status里记录的各个server 的运行状态
      BestAvailableRule 选择一个最小的并发请求的server,逐个考察server, 如果Server被tripped了,则跳过
      RandomRule 随机选择一个Server
      WeightedResponseTimeRule 根据响应时间加权,响应时间越长,权重越小,被选中的可能性越低
      RetryRule 对选定的负载均衡策略加上重试机制,在一个配置时间段内当 选择Server不成功,则一直尝试使用subRule的方式选择一个 可用的Server
      RoundRobinRule 轮询选择,轮询index,选择index对应位置的Server
      ZoneAvoidanceRule 复合判断Server所在区域的性能和Server的可用性 选择Server,在没有区域的环境下,类似于轮询(RandomRule)
    2. 修改策略为随机:

      RibbonConfig.java 新增配置[全局]

      java 复制代码
      /**
       * 配置轮询策略为RandomRule
       * 其他的策略配置也一样,策略类路径都是 com.netflix.loadbalancer.xxx
       */
      @Bean
      public IRule ribbonRule(){
          return new RandomRule();
      }

      或:按服务粒度进行配置:(demo-hello 是目标服务的服务名)

      yaml 复制代码
      demo-hello:
        ribbon:
          NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

      我直接配置全局的 ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule不生效,不知道是不是不支持全局配置。

      效果:

      java 复制代码
      2023-06-23 15:59:31.095  INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController   : i-0: BaseResp(code=200, data=Response from server port: 8082, msg=success)
      2023-06-23 15:59:31.097  INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController   : i-1: BaseResp(code=200, data=Response from server port: 8084, msg=success)
      2023-06-23 15:59:31.100  INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController   : i-2: BaseResp(code=200, data=Response from server port: 8084, msg=success)
      2023-06-23 15:59:31.104  INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController   : i-3: BaseResp(code=200, data=Response from server port: 8082, msg=success)
      2023-06-23 15:59:31.108  INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController   : i-4: BaseResp(code=200, data=Response from server port: 8084, msg=success)
      2023-06-23 15:59:31.112  INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController   : i-5: BaseResp(code=200, data=Response from server port: 8084, msg=success)
      2023-06-23 15:59:31.117  INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController   : i-6: BaseResp(code=200, data=Response from server port: 8084, msg=success)
      2023-06-23 15:59:31.124  INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController   : i-7: BaseResp(code=200, data=Response from server port: 8082, msg=success)
      2023-06-23 15:59:31.132  INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController   : i-8: BaseResp(code=200, data=Response from server port: 8084, msg=success)
      2023-06-23 15:59:31.137  INFO 11492 --- [nio-8085-exec-3] com.yt.demo.controller.HelloController   : i-9: BaseResp(code=200, data=Response from server port: 8082, msg=success)

Spring Cloud Zuul

zuul-server

  1. 新建项目 [可以从Eureka-client复制,然后修改spring.application.name和pom文件的artifactId]。

  2. 引入Eureka-client依赖和zuul依赖

    xml 复制代码
    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
  3. 启动类加注解: @EnableZuulProxy

  4. application.yml 配置文件,加上zuul配置

    yaml 复制代码
    server:
      port: 8888
    
    spring:
      application:
        name: zuul-server
    
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
    
    # 将 /demo-hello/ 开头的请求,转到demo-hello组件中
    zuul:
      routes:
        demo-hello:
          path: /demo-hello/**
          serviceId: demo-hello
    #      也可以直接设置url
    #      url: http://localhost:8082/
  5. 启动 demo-hello 组件,调用请求: http://localhost:8888/demo-hello/hello/testGet?param=this_is_param,demo-hello[8082] 得到结果。等同于直接调用demo-hello的请求:http://localhost:8082/hello/testGet?param=this_is_param

  6. 路由前缀

    yaml 复制代码
    zuul:
      routes:
        demo-hello:
          path: /demo-hello/**
          serviceId: demo-hello
      prefix: /pre

    我们可以配置zuul.prefix来设置统一前缀。像我这样配置的话,就是得访问:http://localhost:8888/pre/demo-hello/hello/testGet?param=this_is_param,才能跟上面的请求等效。

  7. 屏蔽服务、路径

    yaml 复制代码
    zuul:
      ignored-services: demo-hello
      ignored-patterns: /**/hello/**

请求过滤

  1. 我们可以根据过滤规则,对访问的请求进行校验。不符合规则的可以直接过滤返回。比如我们可以校验请求的参数是否有token参数。

  2. 新建过滤器:

    java 复制代码
    @Slf4j
    public class AccessFilter extends ZuulFilter {
        /**
         * 过滤器类型
         * pre: 在请求被路由前调用
         * routing: 在路由请求时调用
         * error: 在处理请求时发生错误时调用
         * post: 在routing和error过滤器之后调用
         */
        @Override
        public String filterType() {
            return "pre";
        }
    
        /**
         * 过滤器的执行顺序,数值越小越优先
         */
        @Override
        public int filterOrder() {
            return 0;
        }
    
        /**
         * 是否启用过滤
         */
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        /**
         * 具体过滤逻辑
         */
        @Override
        public Object run() throws ZuulException {
            RequestContext currentContext = RequestContext.getCurrentContext();
            HttpServletRequest request = currentContext.getRequest();
    
            log.info("zuul接收到请求,参数:{}", request.getParameterMap());
            log.info("zuul接收到请求,参数:{}", request.getParameter("token"));
    
            if (request.getParameterMap().get("token") == null) {
                log.info("请求参数未包含token字段,返回");
                currentContext.setResponseStatusCode(401);
                currentContext.setSendZuulResponse(false);
                return null;
            }
    
            log.info("正常请求,放行");
            return null;
        }
    }
  3. 创建bean

    java 复制代码
    @Slf4j
    @Configuration
    public class ZuulConfig {
        @Bean
        public AccessFilter accessFilter() {
            return new AccessFilter();
        }
    }
  4. 测试

    请求 http://localhost:8888/pre/demo-hello/hello/testGet?param=this_is_param&token=gyt%26kal13 可以正常调到demo-hello组件里的方法。

    请求http://localhost:8888/pre/demo-hello/hello/testGet?param=this_is_param返回401错误码

Spring Cloud Config

config-server

  1. 引入依赖

    xml 复制代码
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
  2. 启动类添加注解 @EnableConfigServer

  3. bootstrap.yaml配置

    yaml 复制代码
    server:
      port: 8086
    
    spring:
      application:
        name: config-server
    
      cloud:
        config:
          server:
            git:
              uri: https://gitee.com/Aes_yt/spring-cloud-demo.git
    #          git 仓库的相对搜索路径
              search-paths: config-repo
              username: xxxx
              password: xxxx
              default-label: master
  4. git 配置

    第三点使用的是git配置,所以我们需要有一个git仓库。我已经事先建好了,配置文件放在git仓库的config-repo路径下。

    在config-repo上传配置文件,例如上传不同环境的三个配置文件:

    config-client.yaml

    yaml 复制代码
    config:
      name: myConfig

    config-client-dev.yaml

    yaml 复制代码
    config:
      name: myConfig-dev

    config-client-test.yaml

    yaml 复制代码
    config:
      name: myConfig-test

    config-client 是我待会要创建的client项目的application.name,文件名的明明规则就是 {name}-{profile}.yaml 或 .properties。文件内容的配置文件就跟普通的yaml项目一样,配置所需要的一些配置,我这边是随便配置了一个变量名 ${config.name},后面再输出打印测试。

  5. 先测试。启动config-server,访问地址 : http://localhost:8086/config-client/dev,可以看到输出配置信息。

    json 复制代码
    {
    	"name": "config-client",
    	"profiles": ["dev"],
    	"label": null,
    	"version": "2ec77d4a4f8050fa5a032cf5ff27ff8583d3f663",
    	"state": null,
    	"propertySources": [{
    		"name": "https://gitee.com/Aes_yt/spring-cloud-demo.git/config-repo/config-client-dev.yaml",
    		"source": {
    			"config.name": "myConfig-dev"
    		}
    	}, {
    		"name": "https://gitee.com/Aes_yt/spring-cloud-demo.git/config-repo/config-client.yaml",
    		"source": {
    			"config.name": "myConfig"
    		}
    	}]
    }

    也可以直接访问 http://localhost:8086/config-client-dev.yaml 查看yaml配置内容

    yaml 复制代码
    config:
      name: myConfig-dev

config-client

  1. 引入maven依赖

    xml 复制代码
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
  2. bootstrap.yaml配置(我这里用application.yaml 配置启动会报错)

    yaml 复制代码
    spring:
      application:
        name: config-client
      cloud:
        config:
          label: master
    #     config-server的地址
          uri: http://localhost:8086/
    #      环境
          profile: dev
    
    server:
      port: 8087
  3. 新建一个测试类,检测配置值

    java 复制代码
    @RestController
    @RequestMapping("/config")
    public class ConfigTestController {
        @Value("${config.name}")
        private String configName;
    
        @GetMapping("/test")
        public String test() {
            return configName;
        }
    }
  4. 启动项目,能看到控制台输出,会打印出当前使用的配置信息

    less 复制代码
    2023-07-22 10:42:16.447  INFO 13592 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://localhost:8086/
    2023-07-22 10:42:17.480  INFO 13592 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=config-client, profiles=[dev], label=master, version=2ec77d4a4f8050fa5a032cf5ff27ff8583d3f663, state=null

    能看出当前环境是 name=config-client, profiles=[dev], label=master ,所以会去maven仓库找到master分支的 config-client-dev 的配置文件。如果找不到的话,在 @Value("${config.name}") 时则会报错。

  5. 测试,访问 http://localhost:8087/config/test

    myConfig-dev

结合Eureka

  1. 结合Eureka使用,首先server和client都要引入Eureka-client依赖,pom中引入spring-cloud-starter-netflix-eureka-client 。其次,启动类都要加上 @EnableDiscoveryClient 注解。最后yaml中都需要加上配置 eureka.client.service-url.defaultZone=http://localhost:8761/eureka/ ,这三个都可参考上文的Eureka-client配置。

  2. config-client加上discovery配置:

    yaml 复制代码
    spring:
      application:
        name: config-client
      cloud:
        config:
          label: master
          #     config-server的地址
    #      uri: http://localhost:8086/
          #      环境
          profile: dev
    
    #      使用eureka发现服务
          discovery:
            enabled: true
            service-id: config-server
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
    
    server:
      port: 8087

Spring Cloud Sleuth

Sleuth 能够对服务间调用的链路进行监控追踪,之前学习 Feign 的时候,我们用 Feign-client 组件,调用了 demo-hello 组件的testGet方法,所以我们可以在之前的Feign-client 和 demo-hello 组件的基础上进行修改验证,添加Sleuth依赖,来观察服务间的调用情况。

  1. 添加Sleuth依赖

  2. 运行,调用,观察打印的日志

    feign-client:

    xml 复制代码
    2023-07-23 10:10:11.296 DEBUG [feign-client,f307a05d85938646,f8b404471ba7448a,true] 15956 --- [ix-demo-hello-5] 
    2023-07-23 10:10:11.296 DEBUG [feign-client,f307a05d85938646,f8b404471ba7448a,true] 15956 --- [ix-demo-hello-5] 
    2023-07-23 10:10:11.416 DEBUG [feign-client,f307a05d85938646,f8b404471ba7448a,true] 15956 --- [ix-demo-hello-5] 
    ...

    demo-hello:

    yaml 复制代码
    2023-07-23 10:10:11.398  INFO [demo-hello,f307a05d85938646,51bf5d6b238302e9,true] 11736 --- [nio-8082-exec-1] com.yt.demo.controller.HelloController   : [demo-hello] testGet:Get method: hello

    可以从控制台的日志发现,日志多了[feign-client,f307a05d85938646,f8b404471ba7448a,true]部分,第一个参数代表application.name,第二个参数 f307a05d85938646 则是一个请求链路的 Trace ID,第三个参数f8b404471ba7448a表示SpanId,是一个基本的工作单元,第四个参数表示是否要将该信息输出到Zipkin等服务中来收集和展示。

    从feign-client 到 demo-hello 中, Trace ID 都是f307a05d85938646,所以可以将一个请求在不同服务中的日志串联起来。

相关推荐
sniper_fandc18 小时前
Spring Cloud系列—SkyWalking告警和飞书接入
spring cloud·skywalking
abigalexy1 天前
深入图解Spring Cloud底层设计
spring·spring cloud
楠有枝3 天前
普通用户使用docker命令
spring cloud·docker·eureka
孤狼程序员3 天前
【Spring Cloud 微服务】2.守护神网关Gateway
spring cloud·微服务·gateway
朱皮皮呀3 天前
Spring Cloud——服务注册与服务发现原理与实现
运维·spring cloud·eureka·服务发现·php
朱皮皮呀4 天前
微服务流量分发核心:Spring Cloud 负载均衡解析
spring cloud·微服务·负载均衡
源码宝5 天前
【智慧工地源码】智慧工地云平台系统,涵盖安全、质量、环境、人员和设备五大管理模块,实现实时监控、智能预警和数据分析。
java·大数据·spring cloud·数据分析·源码·智慧工地·云平台
2301_793086875 天前
SpringCloud 07 微服务网关
java·spring cloud·微服务
创码小奇客6 天前
架构师私藏:SpringBoot 集成 Hera,让日志查看从 “找罪证” 变 “查答案”
spring boot·spring cloud·trae
2301_793086877 天前
SpringCloud 02 服务治理 Nacos
java·spring boot·spring cloud