SpringCloud+eureka/zookeeper+robbin+hystrix+openFeign+zuul/gateway+SpringCloud config+RabbitMQ

本文章僅作為個(gè)人筆記

  • eureka的集成(注冊(cè)中心)

    • 新建springboot項(xiàng)目并在build.gradle文件添加相關(guān)依賴

      ext {
          set('springCloudVersion', "Hoxton.SR4")
      }
      
      dependencies {
          implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
      }
      dependencyManagement {
          imports {
              mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
          }
      }
      
    • 在新建的eureka服務(wù)項(xiàng)目中配置相關(guān)文件(application.yml對(duì)應(yīng)配置可自行更改,下面給的是單機(jī)配置)

      eureka:
        instance:
          hostname: localhost
        # 是否向注冊(cè)中心注冊(cè)服務(wù)(如果單eureka服務(wù)則false/避免自己對(duì)自己注冊(cè)服務(wù))
        client:
          register-with-eureka: false
          # 是否去檢索其它服務(wù),
          fetch-registry: false
          # 指定服務(wù)注冊(cè)中心的位置
          service-url:
              defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      
    • 在新建的eureka服務(wù)項(xiàng)目Application主類添加注解 @EnableEurekaServer

      @EnableEurekaServer
      public class EurekaServerApplication {
      
    • 此時(shí)再啟動(dòng)新建的eureka服務(wù)項(xiàng)目便完成了單eureka服務(wù)注冊(cè)中心的搭建

    • eureka集群的配置

      • 配置文件(在項(xiàng)目中復(fù)制配置文件类垦,并加后綴<application-eureka8761.yml>)

        • 配置文件1

          server:
            port: 8761
          eureka:
            instance:
              hostname: eureka8761
            # 是否向注冊(cè)中心注冊(cè)服務(wù)(如果單eureka服務(wù)則false/避免自己對(duì)自己注冊(cè)服務(wù))
            client:
              register-with-eureka: false
              # 是否去檢索其它服務(wù),
              fetch-registry: false
              # 指定服務(wù)注冊(cè)中心的位置
              service-url:
                  defaultZone: http://eureka8762:eureka8762/eureka/
          
        • 配置文件2

          server:
            port: 8762
          eureka:
            instance:
              hostname: eureka8762
            # 是否向注冊(cè)中心注冊(cè)服務(wù)(如果單eureka服務(wù)則false/避免自己對(duì)自己注冊(cè)服務(wù))
            client:
              register-with-eureka: false
              # 是否去檢索其它服務(wù)徘公,
              fetch-registry: false
              # 指定服務(wù)注冊(cè)中心的位置
              service-url:
                  defaultZone: http://eureka8761:eureka8761/eureka/
          
      • 因?yàn)閔ostname改變了留特,但是本地并不能識(shí)別堂鲤,因此需要更改本地host文件咙咽,添加本地配置

        127.0.0.1 eureka8761
        127.0.0.1 eureka8762
        
    • 運(yùn)行時(shí)命令

      java -jar xxx.jar --spring.profiles.active=<服務(wù)名(eureka8761)>
      
    • eureka常用配置

      // 服務(wù)心跳s
      eureka.instance.lease-renewal-interval-in-seconds=2
      // 服務(wù)判定故障時(shí)間s
      eureka.instance.lease-expiration-duration-in-seconds=10
      
    • 普通服務(wù)提供者/消費(fèi)者接入eureka注冊(cè)中心

      • 提供者注冊(cè)服務(wù)

      • 為服務(wù)提供者項(xiàng)目的build.gradle項(xiàng)目添加eureka相關(guān)依賴

        ext {
          set('springCloudVersion', "Hoxton.SR4")
        }
        
        dependencies {
          implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
        }
        dependencyManagement {
          imports {
              mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
          }
        }
        
      • 為服務(wù)提供者項(xiàng)目的application.yml添加eureka相關(guān)配置(多配置時(shí)service-url以,分隔)

        # 服務(wù)名稱
        spring:
          application:
            name: cloud-provider
        # eureka注冊(cè)中心連接方式
        eureka:
          client:
            service-url: 
              defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
        
      • 在服務(wù)提供者項(xiàng)目的Application主類添加注解 @EnableEurekaClient/@EnableDiscoveryClient 以使配置文件生效并注冊(cè)服務(wù)/表明以可以使用eureka服務(wù)

        @EnableDiscoveryClient
        public class CloudProviderApplication {
        
      • 此時(shí)再啟動(dòng)服務(wù)提供者項(xiàng)目老玛,服務(wù)便注冊(cè)至eureka注冊(cè)中心了

    • 服務(wù)者的調(diào)用

      • 為消費(fèi)者項(xiàng)目的build.gradle項(xiàng)目添加eureka相關(guān)依賴

        ext {
          set('springCloudVersion', "Hoxton.SR4")
        }
        
        dependencies {
          implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
        }
        dependencyManagement {
          imports {
              mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
          }
        }
        
      • 為服務(wù)消費(fèi)者項(xiàng)目的application.yml添加eureka相關(guān)配置(多配置時(shí)service-url以,分隔)

        # 服務(wù)名稱
        spring:
          application:
            name: cloud-consumer
        # eureka注冊(cè)中心連接方式
        eureka:
          client:
            service-url: 
              defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
        
      • 再在消費(fèi)者RestTemplate bean注入的地方加入 @LoadBalanced 注解加入負(fù)載均衡功能

        @Bean
        @LoadBalanced
        public RestTemplate restTemplate() {
        
      • 此時(shí)只需要將服務(wù)消費(fèi)者的restTemplate.getForEntity方法里的host改為服務(wù)提供者名稱即可(例:<restTemplate.getForEntity("http://cloud-provider/provider/hello"...>)

        @RestController
        public class ConsumerController {
        
          @Autowired
          RestTemplate restTemplate;
          
          @RequestMapping("/consumer/hello")
          public String hello() {
              // eureka注冊(cè)服務(wù)調(diào)用方式 直接返回?cái)?shù)據(jù)
              return restTemplate.getForObject("http://cloud-provider/provider/hello"
                          , String.class);
          }
        }
        
    • ribbon負(fù)載均衡的使用

    • 啟動(dòng)多個(gè)服務(wù)提供者并注冊(cè)至注冊(cè)中心(eureka)

    • 在消費(fèi)者RestTemplate bean注入的地方加入 @LoadBalanced 注解

      @Bean
      @LoadBalanced
      public RestTemplate restTemplate() {
      
    • ribbon負(fù)載均衡策略與配置

      • 策略
        • RoundRobinRule 輪詢策略(默認(rèn))
        • RandomRule 隨機(jī)策略
        • RetryRule 重試策略,失敗重試,錯(cuò)誤過(guò)多訪問(wèn)其它服務(wù)
        • AvailabilityFilteringRule 過(guò)濾故障/并發(fā)連接超閾值服務(wù)钧敞,對(duì)剩下的服務(wù)輪詢
        • BestAvailableRule 過(guò)濾訪問(wèn)過(guò)多故障的服務(wù)蜡豹,返回并發(fā)量最小的服務(wù)
        • ZoneAvoidanceRule 綜合判斷性能/可用性,返回更優(yōu)的服務(wù)
    • 配置

      • 配置bean注入

          @Bean
          public IRule iRule() {
              return new RandomRule();//根據(jù)自己的需求返回不同的rule實(shí)例
          }
        
  • Hystrix 集成(熔斷器)

    • 為項(xiàng)目的build.gradle項(xiàng)目添加hystrix相關(guān)配置

      dependencies {
          implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'
      }
      
    • 在項(xiàng)目的Application主類添加注解 @EnableCircuitBreaker

      @EnableCircuitBreaker
      public class CloudProviderApplication {
      
    • 在項(xiàng)目的controller類中添加注解 @HystrixCommand 及方法錯(cuò)誤時(shí)調(diào)用方法

      @HystrixCommand(fallbackMethod = "error")
      public String hystrix() {
          //業(yè)務(wù)處理
      }
      
      public String error() {
          //錯(cuò)誤處理
          return "error";
      }
      
    • 同時(shí) @SpringBootApplication/@EnableEurekaClient/@EnableCircuitBreaker 三個(gè)注解可用 @SpringCloudApplication 代替

    • @EnableDiscoveryClient 與 @EnableEurekaClient 相似

    • hystrix默認(rèn)超時(shí)時(shí)間為1000ms

    • hystrix 常用配置

      // 設(shè)置超時(shí)時(shí)間
      @HystrixCommand(fallbackMethod = "error", commandProperties = {
                  @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
          })
      
    • hystrix的服務(wù)降級(jí)(當(dāng)某個(gè)服務(wù)產(chǎn)生了熔斷溉苛,此服務(wù)將不再被調(diào)用)

    • hystrix的異常處理(當(dāng)調(diào)用者自己拋出了異常余素,此時(shí)也會(huì)觸發(fā)服務(wù)的降級(jí),當(dāng)我們自己發(fā)生異常時(shí)炊昆,只需要在服務(wù)降級(jí)方法中添加一個(gè)Throwable類型的參數(shù)就能夠獲取到拋出的異常類型)

      public String error(Throwable throwable) {
          return "error:" + (throwable == null ? "null" : throwable.getMessage());
      }
      
    • 如果需要拋某些異常給用戶,則直接在 @HystrixCommand 注解中添加 ignoreExceptions = {<忽略的異常類>}

      @HystrixCommand(fallbackMethod = "error", commandProperties = {
                  @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
          }, ignoreExceptions = {
                  Exception.class
          })
      
    • hystrix自定義請(qǐng)求服務(wù)熔斷

      • 自定義類并繼承 com.netflix.hystrix.HystrixCommand 類

      • 覆寫(xiě) run 方法執(zhí)行業(yè)務(wù)邏輯并返回業(yè)務(wù)數(shù)據(jù)

      • 覆寫(xiě) getFallback 方法處理熔斷邏輯

      • 重載構(gòu)造方法傳入必要參數(shù)Setter及RestTemplate

      • 下面給出示例:

          public class MyHystrixCommand extends HystrixCommand<String> {
          
              private RestTemplate restTemplate;
          
              public MyHystrixCommand(Setter setter, RestTemplate restTemplate) {
                  super(setter);
                  this.restTemplate = restTemplate;
              }
          
              @Override
              protected String run() throws Exception {
          //        int b = 10 / 0;//異常模擬
                  return restTemplate.getForObject("http://cloud-provider/provider/hello"
                          , String.class);
              }
          
              @Override
              protected String getFallback() {
                  Throwable throwable = getExecutionException();
                  return "error2:" + (throwable == null ? "null" : throwable.getMessage());
              }
          
          }
        
    • 調(diào)用時(shí)則不再需要寫(xiě)注解威根,而是直接 new 自定義類凤巨,然后調(diào)用 execute 方法返回結(jié)果。

      @RequestMapping("/consumer/hystrix2")
      public String hystrix2() {
          //使用默認(rèn)的setter
          MyHystrixCommand myHystrixCommand = new MyHystrixCommand(
                  com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(""))
                  , restTemplate);
          return myHystrixCommand.execute();
      }
      
    • 異步調(diào)用方法

      MyHystrixCommand myHystrixCommand = new MyHystrixCommand(
              com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(""))
              , restTemplate);
      Future<String> future = myHystrixCommand.queue();
      //可以在這里做一些其它邏輯
      //阻塞方法
      String result = future.get();
      return result;
      
  • hystrix dashboard (hystrix儀表盤(pán)監(jiān)控)接入

    • 新建項(xiàng)目并為項(xiàng)目的build.gradle項(xiàng)目添加hystrix-dashboard相關(guān)配置

      ext {
          set('springCloudVersion', "Hoxton.SR4")
      }
      
      dependencies {
          implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix-dashboard'
      }
      
      dependencyManagement {
          imports {
              mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
          }
      }
      
    • 在項(xiàng)目的Application主類添加注解 @EnableHystrixDashboard

      @EnableHystrixDashboard
      public class HystrixDashboardApplication {
      
    • 啟動(dòng)項(xiàng)目并訪問(wèn) http://<host>:<port>/hystrix (http://localhost:3721/hystrix) 查看服務(wù)是否部署成功

    • 為需要監(jiān)控的項(xiàng)目的build.gradle文件添加依賴

      dependencies {
          implementation 'org.springframework.boot:spring-boot-starter-actuator'
      }
      
    • 為需要監(jiān)控的項(xiàng)目配置springboot監(jiān)控端口的權(quán)限(用來(lái)暴露endpoints洛搀,由于endpoints包含很多敏感信息敢茁,默認(rèn)只可訪問(wèn) health 和 info 兩個(gè)權(quán)限)

      management:
        endpoints:
          web:
            exposure:
              include: hystrix.stream    
      
    • 訪問(wèn) http://<host>:<port>/actuator/hystrix.stream 查看是否部署成功 (例: http://localhost:8081/actuator/hystrix.stream ,記得先訪問(wèn)一個(gè)其它接口留美,否之返回的是ping...)

    • 為消費(fèi)者添加完監(jiān)控依賴再訪問(wèn) http://<host>:<port>/hystrix 彰檬,在title輸入要監(jiān)控的項(xiàng)目名稱,點(diǎn)擊 Monitor Stream 即可查看項(xiàng)目hystrix運(yùn)行情況谎砾。

  • 聲明式服務(wù)消費(fèi) openFeign (hystrix + ribbon 的整合項(xiàng)目) 集成

    • 為消費(fèi)者項(xiàng)目的build.gradle文件添加依賴

      dependencies {
          //本身須包含 spring-cloud-starter-netflix-eureka-client
          implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
      }
      
    • 在項(xiàng)目的Application主類添加注解 @EnableFeignClients

      @EnableFeignClients
      public class FeignConsumerApplication {
      
    • 在項(xiàng)目需要訪問(wèn)注冊(cè)中心的service添加注解 @FeignClient("<服務(wù)名稱,不區(qū)分大小寫(xiě)>")并為方法添加 @RequestMapping("<訪問(wèn)服務(wù)路徑>")注解

      /訪問(wèn)的服務(wù)名稱
      @FeignClient("cloud-provider")
      public interface ProviderService {
      
          //訪問(wèn)的服務(wù)路徑
          @RequestMapping("/provider/hello")
          public String hello();
      
      }
      
    • 為服務(wù)消費(fèi)者項(xiàng)目的application.yml添加相關(guān)配置(多配置時(shí)service-url以,分隔)

      # 服務(wù)名稱
      spring:
        application:
          name: feign-consumer
      # eureka注冊(cè)中心連接方式
      eureka:
        client:
          service-url: 
            defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
      
    • openFeign 開(kāi)啟熔斷機(jī)制

      • 在 application.yml 配置文件添加配置

          feign:
            hystrix:
              enabled: true
        
      • 在Service的 @FeignClient 注解中添加 fallback 賦值

          @FeignClient(name = "cloud-provider", fallback = ProviderFallBack.class)
          public interface ProviderService {
        
      • 自定義的 ProviderFallBack 須實(shí)現(xiàn)對(duì)應(yīng)的Service接口逢倍,當(dāng)熔斷時(shí)調(diào)用實(shí)現(xiàn)的方法

          @Component
          public class ProviderFallBack implements ProviderService {
          
              @Override
              public String hello() {
                  System.out.println("服務(wù)不可用時(shí)調(diào)用");
                  return "fall back.";
              }
          }
        
    • openFeign獲取服務(wù)熔斷異常信息

      • 在 @FeignClient 注解中賦值屬性 fallbackFactory

          @FeignClient(name = "cloud-provider", fallbackFactory = ProviderFallBackFactory.class)
        
      • 編寫(xiě) ProviderFallBackFactory 類,實(shí)現(xiàn) FallbackFactory 接口并重寫(xiě)相應(yīng)方法景图,其中create方法里邊的cause即報(bào)錯(cuò)信息较雕。

          @Component
          public class ProviderFallBackFactory implements FallbackFactory<ProviderService> {
          
              @Override
              public ProviderService create(Throwable cause) {
                  return new ProviderService() {
                      @Override
                      public String hello() {
                          System.out.println("服務(wù)不可用時(shí)調(diào)用 factory.");
                          return cause.getMessage();
                      }
                  };
              }
          }
        
  • zuul 集成(api網(wǎng)關(guān))

    • 新建項(xiàng)目并為項(xiàng)目的build.gradle文件添加依賴

      dependencies {
          implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
          implementation 'org.springframework.cloud:spring-cloud-starter-netflix-zuul'
      }
      
    • 在項(xiàng)目的Application主類添加注解 @EnableZuulProxy 開(kāi)啟zuul功能

      @EnableZuulProxy
      public class ZuulServerApplication {
      
    • 為項(xiàng)目的application.yml添加相關(guān)配置(多配置時(shí)service-url以,分隔)

      # 服務(wù)名稱
      spring:
        application:
          name: zuul-server
      # eureka注冊(cè)中心連接方式
      eureka:
        client:
          service-url: 
            defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
      # 經(jīng)典路由配置(與簡(jiǎn)化配置2選1)
      zuul:
        routes:
          <自定義名字>:
            path: /api-mys/**
            serviceId: cloud-provider
      # 簡(jiǎn)化路由配置(與經(jīng)典配置2選1)
      zuul:
        routes:
          cloud-provider: /api-mys/**
      
      • 其中自定義名字必須對(duì)應(yīng)path和serviceId,意為serviceId指向path,其中serviceId為訪問(wèn)的服務(wù)名,path為項(xiàng)目中訪問(wèn)路徑亮蒋,當(dāng)前規(guī)則為匹配所有 /api-mys/** 的請(qǐng)求扣典,只要請(qǐng)求路徑包含 /api-mys/ 則會(huì)被轉(zhuǎn)發(fā)到cloud-provider上

      • 如果什么配置都不寫(xiě),默認(rèn)也會(huì)幫我們做代理慎玖,默認(rèn)為

        zuul:
          routes:
            <服務(wù)名>: /<服務(wù)名>/**
        
      • 訪問(wèn)host://<host>:<port>/<配置服務(wù)名>/<配置路徑> 測(cè)試(例: http://localhost:8085/api-mys/provider/hello )

    • 為zuul添加過(guò)濾器

      • 創(chuàng)建 Filter 類并繼承ZuulFilter類重寫(xiě)相應(yīng)方法

      • filterType 方法表示當(dāng)前filter在哪個(gè)生命周期運(yùn)行 pre->routing->post error任意階段錯(cuò)誤執(zhí)行

        • pre 表示在路由之前執(zhí)行
        • post 表示請(qǐng)求完成后執(zhí)行
        • error 表示錯(cuò)誤時(shí)執(zhí)行
        • route 表示環(huán)繞請(qǐng)求前后執(zhí)行
        • static 表示
        • 最后還可以自定義
      • filterOrder 方法表示執(zhí)行順序贮尖,當(dāng)filter很多時(shí),根據(jù)這個(gè)值的大小進(jìn)行排序趁怔,

      • shouldFilter 方法判斷當(dāng)前過(guò)濾器是否需要執(zhí)行

      • run 方法則是具體過(guò)濾邏輯

      • 示例代碼:

          @Component
          public class AuthFilter extends ZuulFilter {
          
              @Override
              public String filterType() {
                  return "pre";
              }
          
              @Override
              public int filterOrder() {
                  return 10;
              }
          
              @Override
              public boolean shouldFilter() {
                  return true;
              }
          
              @Override
              public Object run() throws ZuulException {
                  RequestContext requestContext = RequestContext.getCurrentContext();
                  HttpServletRequest request = requestContext.getRequest();
                  String token = request.getParameter("token");
                  if (token == null) {
                      //是否轉(zhuǎn)發(fā)
                      requestContext.setSendZuulResponse(false);
                      requestContext.setResponseStatusCode(401);
                      requestContext.addZuulResponseHeader("content-type", "text/html;charset=utf-8");
                      requestContext.setResponseBody("非法訪問(wèn)");
                  }
                  //目前返回值無(wú)意義湿硝,可以返回null
                  return null;
              }
          }
        
    • 忽略路由規(guī)則

      • 在 application.yml 文件添加配置
        • 忽略所有服務(wù)

            zuul:
                ignored-services: cloud-provider
          
        • 忽略 某個(gè)/某些 路徑

            zuul:
                ignored-patterns: /provider/hello
          
        • 為路由添加前綴

            zuul:
              prefix: /api-mys
          
    • zuul錯(cuò)誤處理

    • 禁用默認(rèn)錯(cuò)誤處理器

      zuul:
        SendErrorFilter:
          error:
            disable: true
      
    • 創(chuàng)建 Filter 類并繼承ZuulFilter類重寫(xiě)相應(yīng)方法衰齐,與之前差異僅filterType返回"error"及run中的處理差異柏副,下面給出示例:

      @Component
      public class ErrorFilter extends ZuulFilter {
      
          @Override
          public String filterType() {
              return "error";
          }
      
          @Override
          public int filterOrder() {
              return 10;
          }
      
          @Override
          public boolean shouldFilter() {
              return true;
          }
      
          @Override
          public Object run() throws ZuulException {
              try {
                  RequestContext requestContext = RequestContext.getCurrentContext();
                  ZuulException exception = (ZuulException) requestContext.getThrowable();
                  System.out.println("系統(tǒng)異常攔截:" + exception);
                  HttpServletResponse response = requestContext.getResponse();
                  response.setContentType("application/json; charset=utf8");
                  response.setStatus(exception.nStatusCode);
                  PrintWriter writer = null;
                  try {
                      writer = response.getWriter();
                      writer.println("{\"code\":" + exception.nStatusCode
                              + ",\"message\":\"" + exception.getMessage() + "\"}");
                  } catch (IOException e) {
                      e.printStackTrace();
                  } finally {
                      if (writer != null) {
                          writer.close();
                      }
                  }
              } catch (Exception e) {
                  ReflectionUtils.rethrowRuntimeException(e);
              }
              //目前返回值無(wú)意義,可以返回null
              return null;
          }
      }
      
    • 自定義全局錯(cuò)誤頁(yè)面(與自定義錯(cuò)誤處理不兼容)

      • 自定義controller并實(shí)現(xiàn) ErrorController 接口报破,實(shí)現(xiàn)相應(yīng)方法任连,下面給出示例:

          @RestController
          public class AllErrorController implements ErrorController {
              @Override
              public String getErrorPath() {
                  //訪問(wèn)哪個(gè)路徑
                  return "/error";
              }
          
              @RequestMapping("/error")
              public Object error() {
                  RequestContext context = RequestContext.getCurrentContext();
                  ZuulException exception = (ZuulException) context.getThrowable();
                  //具體處理看個(gè)人需求
                  return exception.nStatusCode + "--" + exception.getMessage();
              }
          
          }
        
  • Spring Cloud Config (分布式配置管理系統(tǒng))

    • Spring Cloud 默認(rèn)情況使用git存放配置文件蚤吹,也可使用svn/gitlab等
    • SpringCloud Config 服務(wù)搭建
    • Spring Cloud Config 服務(wù)端搭建(服務(wù)端作為中心)
      • 新建項(xiàng)目并為項(xiàng)目 build.gradle 添加相應(yīng)依賴

          ext {
              set('springCloudVersion', "Hoxton.SR4")
          }
          
          dependencies {
              implementation 'org.springframework.cloud:spring-cloud-config-server'
          }
          
          dependencyManagement {
              imports {
                  mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
              }
          }
        
      • 在項(xiàng)目的Application主類添加注解 @EnableConfigServer 開(kāi)啟功能

          @EnableConfigServer
          public class ConfigServerApplication {
        
      • 在項(xiàng)目的 application.yml 中配置git倉(cāng)庫(kù)信息 (這里使用的自己搭建的本地gitlab)

          spring:
            cloud:
              config:
                server:
                  git:
                    uri: http://git.woaizhuangbi.com/makai/springconfigdemo.git
                    search-paths: config-center
                    username: springconfigdemo
                    password: admin1234
        
      • 此時(shí)再啟動(dòng)項(xiàng)目便配置好了配置服務(wù)中心

      • 為了測(cè)試可以在項(xiàng)目下創(chuàng)建文件以測(cè)試

        • 在根目錄創(chuàng)建config-center文件夾

        • 在config-center文件夾下創(chuàng)建application.properties/application-dev.properties/application-test.properties/application-online.yml 文件

        • 在不同文件設(shè)置不同配置(支持.yml文件與.properties文件)

          application.properties
            url=http://www.woaizhuangbi.com
          application-test.properties
            url=http://test.woaizhuangbi.com
          application-online.yml
            url:
                http://online.woaizhuangbi.com
          application-dev.properties
            url=http://dev.woaizhuangbi.com
          
        • 配置文件大致取名規(guī)則

          • /{application}/{profile}[/{label}]
          • /{application}-{profile}.yml
          • /{label}/{application}-{profile}.yml
          • /{application}-{profile}.properties
          • /{label}/{application}-{profile}.properties
      • 訪問(wèn)指定路徑獲取指定配置 http://<host>:<port>/<配置文件前綴>/<配置文件中綴>/<分支> 例: http://localhost:3721/application/online/master

    • Spring Cloud Config 客戶端搭建(可以理解為所有需要獲取動(dòng)態(tài)配置的項(xiàng)目,可以是所有服務(wù))
      • 為項(xiàng)目 build.gradle 添加相應(yīng)依賴

          dependencies {
              implementation 'org.springframework.cloud:spring-cloud-starter-config'
          }
        
      • 創(chuàng)建 bootstrap.yml 文件并配置 name對(duì)應(yīng)配置文件前綴随抠,profile對(duì)應(yīng)中綴裁着,label對(duì)應(yīng)分支,uri即根訪問(wèn)路徑

          spring:
            application:
              name: config-client
            cloud:
              config:
                profile: dev
                label: master
                uri: http://localhost:3721/
        
      • 創(chuàng)建controller進(jìn)行測(cè)試,可以直接使用 @Value("${配置名}") 的方式或者 @Environment 的方式進(jìn)行數(shù)據(jù)獲取拱她,例:

          @RestController
          public class ConfigController {
          
              @Value("${url}")
              private String url;
          
              @Autowired
              private Environment environment;
          
              @RequestMapping("/cloud/url")
              public String url() {
                  return environment.getProperty("url");
          //        return url;
              }
          
          }            
        
      • 這樣就簡(jiǎn)單的完成配置的使用

  • SpringCloud Config 動(dòng)態(tài)更新

    • 客戶端處理

      • 為config客戶端項(xiàng)目的 build.gradle 添加相應(yīng)依賴

          dependencies {
              implementation 'org.springframework.boot:spring-boot-starter-actuator'
          }
        
      • 在服務(wù)端項(xiàng)目的 bootstrap.yml 文件中添加暴露監(jiān)控端點(diǎn)配置及服務(wù)注冊(cè)配置

          management:
            endpoint:
              web:
                exposure:
                  include: "*"
        
      • 在controller上面添加 @RefreshScope 注解

          @RefreshScope
          public class ConfigController {
        
      • 最后發(fā)送一個(gè)post請(qǐng)求給每個(gè)客戶端二驰,以動(dòng)態(tài)刷新 curl -X POST "http://<host>:<port>/actuator/refresh" 例如:

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

      • 此時(shí)再請(qǐng)求發(fā)送過(guò)post請(qǐng)求的客戶端就能獲取最新的配置了

    • SpringCloud Config 安全保護(hù)

      • 服務(wù)端處理

        • 為config服務(wù)端項(xiàng)目的 build.gradle 添加相應(yīng)依賴

          dependencies {
              implementation 'org.springframework.cloud:spring-cloud-starter-security'
          }
          
        • 在服務(wù)端項(xiàng)目的 application.yml 文件中配置用戶名密碼

          spring:
            security:
              user:
                name: springconfigadmin
                password: admin1234
          
        • 此時(shí)再直接訪問(wèn)服務(wù)端的url便需要登錄了

      • 客戶端處理

        • 在客戶端項(xiàng)目的 bootstrap.yml 文件中配置用戶名密碼

          spring:
            cloud:
              config:
                username: springconfigadmin
                password: admin1234
          
  • rabbitMQ 安裝(docker安裝)

    • 拉取鏡像

      docker pull rabbitmq
      docker pull rabbitmq:management
      
    • 運(yùn)行鏡像(這里僅單機(jī),端口自定義指定,詳細(xì)集群等這里不深究)

      docker run -p 4369:4369 -p 5672:5672 -p 15672:15672 -p 25672:25672 --name rabbitmq -d rabbitmq:management
      
    • 默認(rèn)端口

      • 4369 -- erlang發(fā)現(xiàn)口
      • 5672 --client端通信口
      • 15672 -- 管理界面ui端口
      • 25672 -- server間內(nèi)部通信口
    • 默認(rèn)訪問(wèn)地址 http://localhost:15672

    • 默認(rèn)用戶名密碼:

      guest
      guest
      
  • SpringCloud Bus 集成(消息總線/配合rabbitMQ或者kafka使用/這里使用rabbitMQ)

    • 服務(wù)端處理

      • 為config服務(wù)端項(xiàng)目的 build.gradle 添加相應(yīng)依賴

          dependencies {
              implementation 'org.springframework.cloud:spring-cloud-starter-bus-amqp'
          }
        
      • 在服務(wù)端項(xiàng)目的 application.yml 文件中配置rabbitmq相關(guān)配置及暴露bus刷新配置的端點(diǎn)配置

          spring:
            rabbitmq:
              host: 192.168.3.6
              port: 5672
              username: guest
              password: guest
          management:
            endpoints:
              web:
                exposure:
                  include: 'bus-refresh'
        
    • 客戶端處理

      • 為config客戶端項(xiàng)目的 build.gradle 添加相應(yīng)依賴

          dependencies {
              implementation 'org.springframework.cloud:spring-cloud-starter-bus-amqp'
          }
        
      • 在客戶端項(xiàng)目的 application.yml 文件中配置rabbitmq相關(guān)配置

          spring:
            rabbitmq:
              host: 192.168.3.6
              port: 5672
              username: guest
              password: guest
        
    • 最后發(fā)送一個(gè)post請(qǐng)求給服務(wù)端,以動(dòng)態(tài)刷新 curl -X POST "http://<host>:<port>/actuator/bus-refresh" 例如(這里如果開(kāi)啟了登錄則會(huì)沖突):

      curl -X POST "http://localhost:3722/actuator/bus-refresh"
      
    • 此時(shí)再請(qǐng)求所有的客戶端就都能獲取最新的配置了

    • 動(dòng)態(tài)刷新定點(diǎn)通知(只通知部分客戶端)

    • 指定某一個(gè)通知: http://<server_host>:<server_port>/actuator/bus-refresh/{destination} 例:

      http://localhost:3721/actuator/bus-refresh/config-client:3722
      
  • zookeeper 的集成(注冊(cè)中心)

    • docker 常用命令

      • docker實(shí)例查看

        docker ps -a
        
      • docker復(fù)制文件

        docker cp <local path> <applicationID>:<docker path>
        
      • docker登錄

        docker exec -i -t <applicationID> /bin/sh
        
    • zookeeper 在 docker 下運(yùn)行

    • 拉取鏡像

      docker pull zookeeper
      
    • 運(yùn)行鏡像(這里僅單機(jī),端口自定義指定,詳細(xì)集群等這里不深究)

      docker run -p 8080:8080 -p 2181:2181 --name zookeeper -d zookeeper
      
    • 訪問(wèn) http://<host>:<port> 測(cè)試服務(wù)是否能正常訪問(wèn)

  • zookeeper 接入

    • 注冊(cè)服務(wù)至zookeeper
      • 服務(wù)提供者項(xiàng)目的 build.gradle 添加相應(yīng)依賴

          dependencies {
              implementation 'org.springframework.cloud:spring-cloud-starter-zookeeper-discovery'
          }
        
      • 服務(wù)提供者項(xiàng)目的 application.yml 文件中添加相應(yīng)配置

          spring:
            cloud:
              zookeeper:
                connect-string: 192.168.3.6:2181
        
      • 在服務(wù)提供者項(xiàng)目的Application主類添加注解 @EnableDiscoveryClient 以使配置文件生效并注冊(cè)服務(wù)

          @EnableDiscoveryClient
          public class CloudProviderApplication {
        
      • 此時(shí)服務(wù)提供者的服務(wù)便注冊(cè)至zookeeper了

    • 服務(wù)消費(fèi)者的接入
      • 服務(wù)消費(fèi)者項(xiàng)目的 build.gradle 添加相應(yīng)依賴

          dependencies {
              implementation 'org.springframework.cloud:spring-cloud-starter-zookeeper-discovery'
          }
        
      • 服務(wù)消費(fèi)者項(xiàng)目的 application.yml 文件中添加相應(yīng)配置

          spring:
            cloud:
              zookeeper:
                connect-string: 192.168.3.6:2181
        
      • (后面的流程與eureka無(wú)異)

      • 再在消費(fèi)者RestTemplate bean注入的地方加入 @LoadBalanced 注解加入負(fù)載均衡功能

          @Bean
          @LoadBalanced
          public RestTemplate restTemplate() {
        
      • 此時(shí)只需要將服務(wù)消費(fèi)者的restTemplate.getForEntity方法里的host改為服務(wù)提供者名稱即可(例:<restTemplate.getForEntity("http://cloud-provider/provider/hello"...>)

          @RestController
          public class ConsumerController {
          
              @Autowired
              RestTemplate restTemplate;
              
              @RequestMapping("/consumer/hello")
              public String hello() {
                  // eureka注冊(cè)服務(wù)調(diào)用方式 直接返回?cái)?shù)據(jù)
                  return restTemplate.getForObject("http://cloud-provider/provider/hello"
                              , String.class);
              }
          }
        
  • gateway 集成(api網(wǎng)關(guān))

    • 基本概念 Predicate->Filter->Route

    • 新建項(xiàng)目并為項(xiàng)目 build.gradle 添加相應(yīng)依賴

      ext {
          set('springCloudVersion', "Hoxton.SR4")
      }
      
      dependencies {
          implementation 'org.springframework.cloud:spring-cloud-starter-zookeeper-discovery'
      }
      
      dependencyManagement {
          imports {
              mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
          }
      }
      
    • 在項(xiàng)目的Application主類添加注解 @EnableDiscoveryClient 將服務(wù)注冊(cè)至注冊(cè)中心

      @EnableDiscoveryClient
      public class GatewayServerApplication {
      
    • 在項(xiàng)目的 application.yml 中配置相應(yīng)的路由/服務(wù)/斷言等(路由可多個(gè))

      spring:
        cloud:
          gateway:
            discovery:
              locator:
                enabled: true     # 開(kāi)啟從注冊(cè)中心動(dòng)態(tài)創(chuàng)建路由的功能秉沼,利用服務(wù)名進(jìn)行路由
            routes:
              - id: cloud-provider            # 路由的id桶雀,沒(méi)有固定規(guī)則但要求唯一,建議配合服務(wù)名
      #          uri: http://localhost:8080    # 匹配提供服務(wù)的服務(wù)根地址
                uri: lb://cloud-provider    # 匹配后提供服務(wù)的路由地址
                predicates:
                  - Path=/provider/**    # 斷言唬复,路徑相匹配的進(jìn)行路由
      
      • predicates這個(gè)配置除了Path還有其它參數(shù)
        • After 之前 - After=2020-05-23T15:15:21.234+08:00[Asia/Shanghai] # 指定時(shí)間之后可訪問(wèn)
        • Before 之前 - Before=2020-06-23T15:15:21.234+08:00[Asia/Shanghai] # 指定時(shí)間之前可以訪問(wèn)
        • Between 之間 - Between=2020-06-23T15:15:21.234+08:00[Asia/Shanghai],2020-07-23T15:15:21.234+08:00[Asia/Shanghai] # 指定時(shí)間之間可以訪問(wèn)
        • Cookie 帶Cookie - Cookie=username,aabb # 帶有Cookie且key為username矗积,value為aabb
        • Header 帶Header - Header=X-Request-Id, \d+ # 含X-Request-Id的頭且為數(shù)字
        • Method 指定請(qǐng)求方式 - Method=GET # get請(qǐng)求
        • Path 路徑匹配 - Path=/provider/** # 請(qǐng)求路徑匹配 /provider 開(kāi)頭
        • Query 參數(shù)匹配 - Query=username, \d+ # 帶username參數(shù)且參數(shù)值為數(shù)字
      • filter 官方有詳細(xì)介紹
        • 局部過(guò)濾器
        • 全局過(guò)濾器
        • 自定義過(guò)濾器
          • GlobalFilter 全局過(guò)濾器
          • Ordered 權(quán)重
    • 此時(shí)再啟動(dòng)項(xiàng)目便配置好了相關(guān)網(wǎng)關(guān)服務(wù)了

    • 可以訪問(wèn) http://<host>:<port>/<具體路徑> 例: http://localhost:8087/provider/hello

  • SpringCloud Stream 綁定器(兼容所有MQ(目前僅支持RabbitMQ/Kafka))

    • 常用注解

      • @Input 注解標(biāo)識(shí)輸入通道,通過(guò)該通道接收到的消息進(jìn)入應(yīng)用程序
      • @Output 注解標(biāo)識(shí)輸入通道敞咧,發(fā)布的消息將通過(guò)該通道離開(kāi)應(yīng)用程序
      • @StreamListener 監(jiān)聽(tīng)隊(duì)列棘捣,用于消費(fèi)者隊(duì)列的消息接收
      • @EnableBinding 指信道channel和exchange綁定在一起
    • 消息提供者者相關(guān)

    • 為消息提供者項(xiàng)目的build.gradle文件添加依賴(此處兼容rabbitMQ)

      dependencies {
          implementation 'org.springframework.cloud:spring-cloud-starter-stream-rabbit'
      }
      
    • 為消息提供者項(xiàng)目的 application.yml 文檔添加對(duì)應(yīng)的配置

      spring:
        cloud:
          stream:
            binders:
              defaultRabbit:
                type: rabbit
                environment:
                  spring:
                    rabbitmq:
                      host: 192.168.3.6
                      port: 5672
                      username: guest
                      password: guest
            bindings:
              output:
                destination: studyExchange
                content-type: application/json
                binder: defaultRabbit
      
    • 創(chuàng)建service接口并實(shí)現(xiàn),再在service實(shí)現(xiàn)類添加 @EnableBinding 注解并定義消息的推送管道休建,再注入消息發(fā)送管道 MessageChannel乍恐,使用時(shí)調(diào)用 output.send(MessageBuilder.withPayload(<message>).build()) 例:

      @EnableBinding(Source.class) //定義消息的推送管道
      public class MessageProviderImpl implements IMessageProvider {
      
          @Resource
          private MessageChannel output;//消息發(fā)送管道
      
          @Override
          public String send() {
              String serial = UUID.randomUUID().toString();
              output.send(MessageBuilder.withPayload(serial).build());
              System.out.println("send:" + serial);
              return serial;
          }
      
      }
      
    • 使用時(shí)直接注入IMessageProvider進(jìn)行消息操作即可

  • 消息消費(fèi)者相關(guān)

    • 為消息消費(fèi)者項(xiàng)目的build.gradle文件添加依賴(此處兼容rabbitMQ)

      dependencies {
          implementation 'org.springframework.cloud:spring-cloud-starter-stream-rabbit'
      }
      
    • 為消息消費(fèi)者項(xiàng)目的 application.yml 文檔添加對(duì)應(yīng)的配置

      spring:
        cloud:
          stream:
            binders:
              defaultRabbit:
                type: rabbit
                environment:
                  spring:
                    rabbitmq:
                      host: 192.168.3.6
                      port: 5672
                      username: guest
                      password: guest
            bindings:
              input:
                destination: studyExchange
                content-type: application/json
                binder: defaultRabbit
      
    • 創(chuàng)建Controller并添加 @EnableBinding 注解定義管道類 Sink.class,創(chuàng)建消息方法添加 @StreamListener 注解定義類型测砂,例:

      @Component
      @EnableBinding(Sink.class)
      public class ReceiveMessageListenerController {
      
          @Value("${server.port}")
          private String serverPort;
      
          @StreamListener(Sink.INPUT)
          public void input(Message<String> message) {
              System.out.println(serverPort + " receive message = " + message);
          }
      
      }
      
    • 使用時(shí) 若收到消息即會(huì)調(diào)用 input(Message<String> message) 方法

    • mq重復(fù)消費(fèi)問(wèn)題

      • 默認(rèn)消息生產(chǎn)者會(huì)發(fā)送給消息給每個(gè)用戶茵烈,即多次消費(fèi)。當(dāng)我們的消息只需要被一個(gè)用戶消費(fèi)時(shí)砌些,需要對(duì)多個(gè)消息消費(fèi)者進(jìn)行共同分組

      • 在多個(gè)消費(fèi)者項(xiàng)目配置文件里添加配置即可瞧毙,例:

        spring:
          cloud:
            stream:
              bindings:
                input:
                  group: config-client
        
    • mq持久化

    • 自定義分組的消息消費(fèi)者掉線后再上線不會(huì)丟失錯(cuò)過(guò)的消息

  • 本人創(chuàng)建一github demo,有需求可自行查看借鑒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宙彪,一起剝皮案震驚了整個(gè)濱河市矩动,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌释漆,老刑警劉巖悲没,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異男图,居然都是意外死亡示姿,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)逊笆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)栈戳,“玉大人,你說(shuō)我怎么就攤上這事难裆∽犹矗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵乃戈,是天一觀的道長(zhǎng)褂痰。 經(jīng)常有香客問(wèn)我,道長(zhǎng)症虑,這世上最難降的妖魔是什么缩歪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮谍憔,結(jié)果婚禮上匪蝙,老公的妹妹穿的比我還像新娘。我一直安慰自己习贫,他們只是感情好逛球,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著沈条,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诅炉。 梳的紋絲不亂的頭發(fā)上蜡歹,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音涕烧,去河邊找鬼月而。 笑死,一個(gè)胖子當(dāng)著我的面吹牛议纯,可吹牛的內(nèi)容都是我干的父款。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼憨攒!你這毒婦竟也來(lái)了世杀?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤肝集,失蹤者是張志新(化名)和其女友劉穎瞻坝,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體杏瞻,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡所刀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捞挥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浮创。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖砌函,靈堂內(nèi)的尸體忽然破棺而出斩披,到底是詐尸還是另有隱情,我是刑警寧澤胸嘴,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布雏掠,位于F島的核電站,受9級(jí)特大地震影響劣像,放射性物質(zhì)發(fā)生泄漏乡话。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一耳奕、第九天 我趴在偏房一處隱蔽的房頂上張望绑青。 院中可真熱鬧,春花似錦屋群、人聲如沸闸婴。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)邪乍。三九已至,卻和暖如春对竣,著一層夾襖步出監(jiān)牢的瞬間庇楞,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工否纬, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吕晌,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓临燃,卻偏偏與公主長(zhǎng)得像睛驳,于是被迫代替她去往敵國(guó)和親烙心。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353