zoukankan      html  css  js  c++  java
  • Spring cloud学习一

    SpringCLoud

    总览

    123

    img

    服务注册/发现&注册中心

    1、Eureka

    服务注册(服务提供者)/发现(服务调用者)&注册中心(服务中介)

    1588323712955

    • 服务注册:

      Eureka 客户端向 Eureka Server 注册时,它提供自身的元数据,比如IP地址、端口,运行状况指示符URL,主页等。

    • 服务续约:

      Eureka 客户会每隔30秒(默认情况下)发送一次心跳来续约。通过续约来告知 Eureka ServerEureka 客户仍然存在,没有出现问题。正常情况下,如果 Eureka Server 在90秒没有收到 Eureka 客户的续约,它会将实例从其注册表中删除。

    • 服务下线

      Eureka客户端在程序关闭时向Eureka服务器发送取消请求。发送请求后,该客户端实例信息将从服务器的实例注册表中删除。该下线请求不会自动完成,它需要调用以下内容:DiscoveryManager.getInstance().shutdownComponent();

    • 服务剔除

      在默认的情况下,当Eureka客户端连续90秒(3个续约周期)没有向Eureka服务器发送服务续约,即心跳,Eureka服务器会将该服务实例从服务注册列表删除,即服务剔除。

    • 获取注册列表信息 Fetch Registries

      Eureka 客户端从服务器获取注册表信息,并将其缓存在本地 。 该注册列表信息定期(每30秒钟)更新一次。 在默认的情况下 Eureka 客户端使用压缩 JSON 格式来获取注册列表的信息。

    • 架构图

      img

    • 步骤

      • 注册中心

        1. pom(版本随父项目)

          父项目

          <!--spring cloud Hoxton.SR1-->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-dependencies</artifactId>
              <version>Hoxton.SR1</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
          

          注册中心

          <!--eureka-server-->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
          </dependency>
          
        2. yml

          fetch-registry为true表示获取注册信息列表,如果该项目就是注册中心,则为false表示不用去获取。

          eureka:
            instance:
              hostname: eureka7001.com #eureka服务端的实例名称
            client:
              register-with-eureka: false     #false表示不向注册中心注册自己。
              fetch-registry: false     #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
              service-url:
              #集群指向其它eureka
                # defaultZone: http://eureka7002.com:7002/eureka/
              #单机就是7001自己
                defaultZone: http://eureka7001.com:7001/eureka/
            #server:
              #关闭自我保护机制,保证不可用服务被及时踢除
              #enable-self-preservation: false
              #eviction-interval-timer-in-ms: 2000
          

          此路径下找到hosts文件C:WindowsSystem32driversetc,并增加一下信息,方便直接通过域名访问

          # springcloud-eureka
          127.0.0.1 eureka7001.com
          127.0.0.1 eureka7002.com
          
        3. 主启动类

          @EnableEurekaServer注解开启Eureka

          @SpringBootApplication
          @EnableEurekaServer
          public class EurekaServerMain7001 {
              public static void main(String[] args) {
                  SpringApplication.run(EurekaServerMain7001.class,args);
              }
          }
          
          
      • 客户端

        1. pom

           <!-- eureka-client -->
           <dependency>
               <groupId>org.springframework.cloud</groupId>
               <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
           </dependency>
          
        2. yml

          eureka:
            client:
              register-with-eureka: true #将自身注册到eureka
              fetch-registry: true
              service-url:
                defaultZone: http://localhost:7001/eureka # http://eureka7001.com:7001/eureka/ 也可以
                # defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  # 集群版
          
        3. 启动类

          @EnableEurekaClient

          @SpringBootApplication
          @EnableEurekaClient
          public class PaymentMain8001 {
              public static void main(String[] args) {
                  SpringApplication.run(PaymentMain8001.class, args);
              }
          }
          
          

    2、Consul

    3、Zookeeper


    服务接口调用

    OpenFeign

    OpenFeign 直接内置了 Ribbon。

    RestTemplateSpring提供的一个访问Http服务的客户端类 。例如以下例子,我们就能通过/judge路径访问到http://localhost:8081//service1

    @Autowired
    private RestTemplate restTemplate;
    // 这里是提供者A的ip地址,但是如果使用了 Eureka 那么就应该是提供者A的名称
    privatestaticfinal String SERVICE_PROVIDER_A = "http://localhost:8081";
    
    @PostMapping("/judge")
    public boolean judge(@RequestBody Request request) {
        String url = SERVICE_PROVIDER_A + "/service1";
        return restTemplate.postForObject(url, request, Boolean.class);
    }
    

    使用有些麻烦。OpenFeign能做到向 域名和IP地址的映射一样进行服务间的调用

    • 实现

      • 消费端
      1. pom

         <!--openfeign-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-openfeign</artifactId>
                </dependency>
        
      2. yml

        将默认等待时间延长,默认为一秒,因为连接远程服务器已经多个项目直接的调用容易造成超时。

        #设置feign客户端超时时间(OpenFeign默认支持ribbon)
        ribbon:
        #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
          ReadTimeout: 5000
        #指的是建立连接后从服务器读取到可用资源所用的时间
          ConnectTimeout: 5000
        
      3. 主启动类

        @SpringBootApplication
        @EnableFeignClients
        public class OrderFeignMain80
        {
            public static void main(String[] args) {
                    SpringApplication.run(OrderFeignMain80.class, args);
            }
        }
        
      4. service

        
        @FeignClient(value = "CLOUD-PAYMENT-SERVICE")
        public interface PaymentFeignService
        {
            @GetMapping(value = "/payment/get/{id}")
            public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
        
            @GetMapping(value = "/payment/feign/timeout")
            public String paymentFeignTimeout();
        }
        
      5. Controller

        Controller 就可以像原来调用 Service 层代码一样调用它了。

        @RestController
        @Slf4j
        public class OrderFeignController
        {
            @Resource
            private PaymentFeignService paymentFeignService;
        
            @GetMapping(value = "/consumer/payment/get/{id}")
            public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id)
            {
                return paymentFeignService.getPaymentById(id);
            }
        
            @GetMapping(value = "/consumer/payment/feign/timeout")
            public String paymentFeignTimeout()
            {
                // OpenFeign客户端一般默认等待1秒钟
                return paymentFeignService.paymentFeignTimeout();
            }
        }
        	
        
      • 提供端

        实现@FeignClient注解标注类的路径映射即可


    负载均衡

    Ribbon(蝴蝶结)

    它是在消费者端进行的负载均衡 。

    • RoundRobinRule:轮询策略。Ribbon默认采用的策略。若经过一轮轮询没有找到可用的provider,其最多轮询 10 轮。若最终还没有找到,则返回 null。(默认
    • RandomRule: 随机策略,从所有可用的 provider 中随机选择一个。
    • RetryRule: 重试策略。先按照 RoundRobinRule 策略获取 provider,若获取失败,则在指定的时限内重试。默认的时限为 500 毫秒。

    实现:

    1. 配置类

      @Configuration
      public class ApplicationContextConfig
      {
          @Bean
          @LoadBalanced
          public RestTemplate getRestTemplate()
          {
              return new RestTemplate();
          }
      }
      

      注意:先启动Eureka,再启动提供端,再启动消费端

    自定义负载均衡算法

    1. 实现 IRule 接口

    2. 修改配置文件或者自定义 Java Config 类。

    3. 不能与启动类在同级包,也不能在启动类同级包的子包下。

      以下启动类在com.lx

      自定义负载均衡在com.myrule

      @Configuration
      public class MySelfRule
      {
          @Bean
          public IRule myRule()
          {
              return new RandomRule();//定义为随机
          }
      }
      
      

    服务熔断降级

    Hystrix(豪猪兽)

    Hystrix是一个库,可通过添加等待时间容限和容错逻辑来帮助您控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点,停止服务之间的级联故障并提供后备选项来实现此目的,所有这些都可以提高系统的整体弹性。

    在微服务场景中,通常会有很多层的服务调用。如果一个底层服务出现问题,故障会被向上传播给用户。我们需要一种机制,当底层服务不可用时,可以阻断故障的传播。这就是断路器的作用。他是系统服务稳定性的最后一重保障。

    在springcloud中断路器组件就是Hystrix。Hystrix也是Netflix套件的一部分。他的功能是,当对某个服务的调用在一定的时间内(默认10000ms),有超过一定次数(默认20次)并且失败率超过一定值(默认50%),(更多详情见HystrixCommandProperties类),该服务的断路器会打开。返回一个由开发者设定的fallback。

    fallback可以是另一个由Hystrix保护的服务调用,也可以是固定的值。fallback也可以设计成链式调用,先执行某些逻辑,再返回fallback。

    Hystrix的作用

    1. 对通过第三方客户端库访问的依赖项(通常是通过网络)的延迟和故障进行保护和控制。
    2. 在复杂的分布式系统中阻止级联故障。
    3. 快速失败,快速恢复。
    4. 回退,尽可能优雅地降级。
    5. 启用近实时监控、警报和操作控制。

    1、服务降级

    情景:

    1. 程序运行异常
    2. 超时
    3. 服务熔断触发服务降级
    4. 线程池/信号量也会导致服务降级

    实现:

    1. pom

      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
      </dependency>
      
    2. 主启动

      @SpringBootApplication
      @EnableEurekaClient
      @EnableCircuitBreaker
      public class PaymentHystrixMain8001 {
          public static void main(String[] args) {
              SpringApplication.run(PaymentHystrixMain8001.class,args);
          }
      
          /**
           *此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
           *ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
           *只要在自己的项目里配置上下面的servlet就可以了
           */
          @Bean
          public ServletRegistrationBean getServlet() {
              HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
              ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
              registrationBean.setLoadOnStartup(1);
              registrationBean.addUrlMappings("/hystrix.stream");
              registrationBean.setName("HystrixMetricsStreamServlet");
              return registrationBean;
          }
      }
      
    3. service

      /**
        * @Description: 正常访问
        * @Param0: id
        **/
      public String paymentInfo_OK(Integer id)
      {
          return "线程池:  "+Thread.currentThread().getName()+"  paymentInfo_OK,id:  "+id+"	"+"O(∩_∩)O哈哈~";
      }
      
      /**
        * @Description: 超时访问/访问异常,2s
        * @Param0: id
        **/
      @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",
                      commandProperties={@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")})
      public String paymentInfo_TimeOut(Integer id)
      {
          int timeSleep=3000;
          try { TimeUnit.MILLISECONDS.sleep(timeSleep); } catch (InterruptedException e) { e.printStackTrace(); }
          return "线程池:  "+Thread.currentThread().getName()+" id:  "+id+"	"+"O(∩_∩)O哈哈~"+"  耗时(毫秒): "+timeSleep;
      }
      /**
        * @Description: 超时处理
        **/
      public String paymentInfo_TimeOutHandler(Integer id)
      {
          return "线程池:  "+Thread.currentThread().getName()+"  8001系统繁忙,请稍后再试,id:  "+id+"	"+"o(╥﹏╥)o";
      }
      /**
        * @Description: 访问异常
        * @Param0: id
        **/
      @HystrixCommand(fallbackMethod = "paymentInfo_ExceptionHandler")
      public String paymentInfo_Exception(Integer id)
      {
          int i=10/0;
          return "线程池:  "+Thread.currentThread().getName()+" id:  "+id+"	"+"O(∩_∩)O哈哈~"+"  结果 "+i;
      }
      /**
        * @Description: 异常处理
        **/
      public String paymentInfo_ExceptionHandler(Integer id)
      {
      
          return "线程池:  "+Thread.currentThread().getName()+"  8001运行报错,请稍后再试,id:  "+id+"	"+"o(╥﹏╥)o";
      }
      
    4. 问题:

      1. 一个方法匹配一个fallback指定的方法
      2. 处理异常方法与我们的主要逻辑代码混合在一起
    5. 改善

      在调用端controller类上加上@DefaultProperties注解,指定整个类的全局降级处理方法

      @RestController
      @DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
      public class OrderOpenFeignController {
      
          @Resource
          PaymentService paymentService;
      
          @Resource
          PaymentHystrixService paymentHystrixService;
      
          @GetMapping("/consumer/payment/get/{id}")
          public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
              return paymentService.getPaymentByid(id);
          }
      
          @GetMapping("/consumer/payment/hystrix/ok/{id}")
          public String paymentInfo_OK(@PathVariable("id") Integer id)
          {
              String result = paymentHystrixService.paymentInfo_OK(id);
              System.out.println("*****result: "+result);
              return result;
          }
      
          @GetMapping("/consumer/payment/hystrix/timeout/{id}")
         /* @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
                  @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
          })*/
          //使用全局处理之后写下面的注解,不加属性代表使用默认的全局处理方法
          @HystrixCommand
          public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
          {
              String result = paymentHystrixService.paymentInfo_TimeOut(id);
              System.out.println("*****result: "+result);
              return result;
          }
      
          public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id){
              return "timeout";
          }
      
          // 下面是全局fallback方法
          public String payment_Global_FallbackMethod()
          {
              return "Global异常处理信息,请稍后再试,/(ㄒoㄒ)/~~";
          }
      
      }
      

    2、服务熔断

    类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示 。

    服务的降级->进而熔断->恢复调用链路

    实现:

    1. ​ service

      //=====服务熔断
      @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
      
      
          @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
          @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 请求次数
          @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 时间窗口期
          @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失败率达到多少后跳闸
      })
      public String paymentCircuitBreaker(@PathVariable("id") Integer id)
      {
          if(id < 0)
          {
              throw new RuntimeException("******id 不能负数");
          }
          String serialNumber = IdUtil.simpleUUID();
      
          return Thread.currentThread().getName()+"	"+"调用成功,流水号: " + serialNumber;
      }
      public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id)
      {
          return "id 不能负数,请稍后再试,/(ㄒoㄒ)/~~   id: " +id;
      }
      
    2. 测试

      通过改变参数访问,当使用负数访问是会触发服务降级,多次降级后服务会自动打开熔断(表现为即使使用正数访问仍然是降级处理),之后逐渐恢复正常处理。

    3、服务监控

    实现:

    1. pom

      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
      </dependency>
      
    2. yml

      9001端口

    3. 主启动类

      @EnableHystrixDashboard

    4. 要求,所有提供服务端都添加actuator

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-actuator</artifactId>
       </dependency>
      
    5. 此版本需要配置路径,才能用一下图片路径访问

      @Bean
          public ServletRegistrationBean getServlet() {
              HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
              ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
              registrationBean.setLoadOnStartup(1);
              registrationBean.addUrlMappings("/hystrix.stream");
              registrationBean.setName("HystrixMetricsStreamServlet");
              return registrationBean;
          }
      

    1588410050258

    1588410010293

    注意:每个颜色的数字对应右上方每个属性,例如,绿色代表成功次数。

    服务网关

    • 网关职责:

        	<img src="https://gitee.com/jklixin/images/raw/master/cloud/aHR0cDovL2Nvcy5yYWluMTAyNC5jb20vbWFya2Rvd24vaW1hZ2UtMjAxOTEwMDgxNjAzMjUwMjEucG5n.jpg" alt="img" style="zoom: 50%;" /> 
      
    • 网关分类与功能:

      img

    1、Gateway

    为微服务架构提供一种简单而有效的统一的API路由管理方式

    img

    1589353262774

    • 实现

      1. pom

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        
      2. yml

        server:
          port:  9527
        spring:
          application:
            name: cloud-gateway
          cloud:
            gateway:
              discovery:
                locator:
                  enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
              routes:
                - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
                  # uri: http://localhost:8001 #匹配后提供服务的路由地址
                  uri: lb://cloud-payment-service #匹配后提供服务的路由地址
                  predicates:
                    - Path=/payment/** # 断言,路径相匹配的进行路由
        eureka:
          instance:
            hostname: cloud-gateway-service
          client: #服务提供者provider注册进eureka服务列表内
            service-url:
              register-with-eureka: true
              fetch-registry: true
              defaultZone: http://eureka7001.com:7001/eureka
        
      3. 主启动

        @SpringBootApplication
        @EnableEurekaClient
        public class GatewayMain9527 {
            public static void main(String[] args) {
                SpringApplication.run(GatewayMain9527.class,args);
            }
        }
        
        
      4. 测试:

        通过端口9527访问服务名为cloud-payment-service的服务,路径匹配时访问成功

    路由转发

    1. 时间匹配

      Predicate 支持设置一个时间,在请求进行转发的时候,可以通过判断在这个时间之前或者之后进行转发。

      predicates:
               - After=2020-01-20T06:06:06+08:00[Asia/Shanghai]
      

      2020/01/20之后访问才会进行转发到对应的服务, Before 同理

    2. Cookie匹配

      Cookie Route Predicate 可以接收两个参数,一个是 Cookie name , 一个是正则表达式,

      predicates:
               - Cookie=ityouknow, kee.e
      

      测试:curl http://localhost:9527 --cookie "ityouknow=kee.e",匹配成功

    3. 请求头匹配

      Header Route Predicate 和 Cookie Route Predicate 一样,也是接收 2 个参数,一个 header 中属性名称和一个正则表达式,这个属性值和正则表达式匹配则执行。

       predicates:
              - Header=X-Request-Id, d+
      

      测试1 curl http://localhost:9527 -H "X-Request-Id:1234" 匹配成功

      测试2 curl http://localhost:9527 -H "X-Request-Id:sfsg" 匹配失败

    4. Host匹配

      Host Route Predicate 接收一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用.号作为分隔符。它通过参数中的主机地址作为匹配规则。

       predicates:
              - Host=**.ityouknow.com
      

      测试 curl http://localhost:9527 -H "Host: www.ityouknow.com" 匹配成功

    5. 请求方式匹配

       predicates:
              - Method=GET
      

      curl 默认是以 GET 的方式去请求

      测试 curl -X POST http://localhost:9527 匹配失败

    6. 请求参数匹配

      • Query Route Predicate 支持传入两个参数,一个是属性名一个为属性值,属性值可以是正则表达式。
       predicates:
              - Query=smile
      

      只要求情中包含该属性即可匹配

      测试 curl localhost:9527?smile=x&id=2 匹配成功。

      • 将 Query 的值以键值对的方式进行配置,这样在请求过来时会对属性值和正则进行匹配
       predicates:
              - Query=keep, pu.
      

      当请求中包含 keep 属性并且参数值是以 pu 开头的长度为三位的字符串才会进行匹配和路由。

      测试1 curl localhost:9527?keep=pub 匹配成功

      测试2 curl localhost:9527?keep=pubx 匹配失败

    7. 请求ip匹配

      Predicate 也支持通过设置某个 ip 区间号段的请求才会路由,RemoteAddr Route Predicate 接受 cidr 符号 (IPv4 或 IPv6) 字符串的列表(最小大小为 1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 地址,16 是子网掩码)。

       predicates:
              - RemoteAddr=192.168.1.1/24
      

      请求的远程地址是 192.168.1.10,则此路由将匹配

    8. 组合匹配

      • 需要满足所有断言条件才会被转发
      • 当满足多个路由时。先匹配先转发原则

    Filter

    下例中表示当含有uname属性是允许访问。

    @Component
    public class FilterConfig implements GlobalFilter,Ordered{
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            System.out.println("进入过滤器");
            String uname=exchange.getRequest().getQueryParams().getFirst("uname");
            if(uname==null){
                //请求路径中没有该属性值
                System.out.println("拒绝访问");
                exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                return exchange.getResponse().setComplete();
            }
            //存在,放行
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    }
    
    

    测试: http://localhost:9527/payment/lb?uname=z3 访问成功

    服务配置中心

    为分布式系统中的外部配置提供服务器和客户端支持。方便部署与运维。有客户端、服务端。

    服务端也称分布式配置中心,是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口。

    客户端则是通过指定配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。默认采用 git,并且可以通过 git 客户端工具来方便管理和访问配置内容。

    优点:

    • 集中管理配置文件
    • 不同环境不同配置,动态化的配置更新
    • 运行期间,不需要去服务器修改配置文件,服务会想配置中心拉取自己的信息
    • 配置信息改变时,不需要重启即可更新配置信息到服务
    • 配置信息以 rest 接口暴露

    实现:

    1. 服务端

      1. pom

        <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-config-server</artifactId>
                </dependency>
        
      2. yml

        spring:
          application:
            name:  cloud-config-server #注册进Eureka服务器的微服务名
          cloud:
            config:
              server:
                git:
                  # uri: git@github.com:zzyybs/springcloud-config.git #GitHub上面的git仓库名字
                  uri: https://gitee.com/jklixin/springcloud-config.git #Gitee上面的git仓库名字
                ####搜索目录
                  search-paths:
                    - springcloud-config
              ####读取分支
              label: master
        
      3. 启动类

        @EnableConfigServer

        @SpringBootApplication
        @EnableConfigServer
        public class ConfigMain3344 {
            public static void main(String[] args) {
                SpringApplication.run(ConfigMain3344.class,args);
            }
        }
        
    2. 客户端

      1. pom

         <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-config</artifactId>
                </dependency>
        
      2. bootstrap.yml

        spring:
          application:
            name: cloud-config-client
          cloud:
            config:
              lable: master 
              name: config  #需要从github上读取的资源名称,注意没有yml后缀名
              profile: dev #本次访问的配置项
              uri: http://localhost:3344 #配置服务端,本微服务启动后先去找3344号服务,通过SpringCloudConfig获取GitHub的服务地址
        
      3. controller

        @RestController
        //@RefreshScope
        public class ConfigController {
        
            @Value("${config.info}")
            String info;
        
            @GetMapping("/configInfo")
            public String getConfigInfo(){
                return info;
            }
        }
        

    访问方式:

    /{application}/{profile}[/{label}]
    /{application}-{profile}.yml
    /{label}/{application}-{profile}.yml
    /{application}-{profile}.properties
    /{label}/{application}-{profile}.properties

    1588476129348

    1588476151356

    问题: 更改gitee上的内容,服务端更新成功,但是客户端并未更新成功

    动态刷新

    解决:

    1. 客户端引入actuator依赖

    2. 暴露监控端点

      # 暴露监控端点
      management:
        endpoints:
          web:
            exposure:
              include: "*"
      
    3. @refreshScope业务类Controller修改

    4. 需要运维发送Post请求刷新3355

      curl -X POST "http://localhost:3355/actuator/refresh"
      

    问题: 多个客户端如何实现动态刷新


    消息总线

    Bus

    Bus支持两种消息代理:RabbitMQ和Kafka

    广播

    实现

    • 服务端

      1. 添加bus-amqp依赖

         <!--添加消息总线RabbitMQ支持-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
                </dependency>
        
      2. 配置rabbitmq相关属性

          #rabbitmq相关配置
          rabbitmq:
            host: 123.56.16.54
            port: 5672
            username: guest
            password: guest
        
      3. 暴露刷新端口

        # 暴露bus刷新的端点
        management:
          endpoints:
            web:
              exposure:
                include: 'bus-refresh'
        
    • 客户端

      1. 添加bus-amqp依赖
      2. 配置rabbitmq相关属性

    测试:

    1. 更改配置文件

    2. 刷新

      http://localhost:3344/config-dev.yml 一致

      http://localhost:3355/configInfo 不一致

    3. 发送请求刷新 curl -X POST "http://localhost:3344/actuator/bus-refresh"

      1588477143566

    4. 刷新

      http://localhost:3355/configInfo 一致

      http://localhost:3366/configInfo 一致

    定点通知

    实现: 公式:http://localhost:3344/actutor/bus-refresh/{destination}

    测试: curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"

    http://localhost:3355/configInfo 一致

    http://localhost:3366/configInfo 不一致


    消息驱动

    Stream

    屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程模型

  • 相关阅读:
    递归---Day29
    File类---Day28
    线程池---Day26
    微信公众号运营人员必备的软件工具网站合集
    消息中间件的技术选型心得-RabbitMQ、ActiveMQ和ZeroMQ
    itoa函数的递归实现(二级指针实现)
    二叉树——查找两个任意节点的最近祖先
    C#多线程(二)
    C#多线程(一)
    Websocket协议之php实现
  • 原文地址:https://www.cnblogs.com/jklixin/p/12887255.html
Copyright © 2011-2022 走看看