SpringCloud_SpringCloudAlibaba程式碼實現完整流程

2020-08-12 20:41:17

SpringCloud

SpringCloudAlibaba

參考鏈接:

建立專案

建立Springboot父專案,只需要一個pom就可以了(AugJungle:生產專案單獨部署)

POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.jungle.springclouddemo</groupId>
    <artifactId>springclouddemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springclouddemo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

pom新增SpringCloudAlibaba依賴

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.1.BUILD-SNAPSHOT</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    #出現問題再引入SpringCloud的包吧,個人感覺不用引入,but寫這個的專案時引入了。。。
                <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

建立子模組後修改子模組中的pom裏面的parent標籤,修改爲父專案中的值

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.jungle.springclouddemo</groupId>
        <artifactId>springclouddemo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.jungle</groupId>
    <artifactId>news</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>news</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

    </dependencies>

    <build>

    </build>

</project>

開啓Nacos Server

文件地址:https://nacos.io/zh-cn/docs/quick-start.html

Windows版Nacos Server直接下載地址:https://download.csdn.net/download/qq_35742333/12697057

下載後進入bin資料夾下執行.\startup.cmd -m standalone

-m:以單機模式執行

註冊Nacos Discovery

注:部分圖片可能無法下載,可以存取我的個人主頁

[外連圖片轉存失敗,源站可能有防盜鏈機制 機製,建議將圖片儲存下來直接上傳(img-X0ExcvZf-1597236593840)(https://s3.ap-northeast-1.wasabisys.com/img.tw511.com/202008/20200810174100vegunxjesst.png)]

子專案匯入依賴

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

maven出現問題:

Could not find artifact com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:pom:unknown in aliyun (https://maven.aliyun.com/repository/public)

Non-resolvable parent POM for com.jungle:news:0.0.1-SNAPSHOT: Could not find artifact com.jungle:springclouddemo:pom:0.0.1-SNAPSHOT and 'parent.relativePath' points at no local POM @ line 5, column 13

問題解決:

父專案新增

不是必須

<modules>
    <module>news</module>
</modules>

​ 必須

父專案記得配一個pom

子專案最好配一個jar

修改組態檔

在application.properties檔案新增spring.profiles.active=dev

新建application-dev.yml檔案,新增設定

server:
  port: 18081
spring:
  cloud:
    nacos:
      discovery:
        #命令空間ID
        namespace: d2f4bb90-17ac-4bc1-9e32-8734e722eb0c
        #叢集
        cluster-name: newMachine
		#分組
        group: 1
		#數據源,可以用來自定義一些數據,供服務進行呼叫,例如兩個服務版本不一致,用來讓不同版本的呼叫不同的服務
        metadata:
          testKey1: testValue1
          testKey2: testValue2
	  #Nacos註冊服務的IP及埠號
      server-addr: 127.0.0.1:8848
  application:
    name: service-news

此時執行子專案,已經可以在Nacos Server上看見註冊的子專案執行服務

DiscoveryClient

服務發現物件,可以用來進行手動服務註冊

@Resource
private DiscoveryClient discoveryClient;

List<ServiceInstance> instances = discoveryClient.getInstances("service-news");

System.out.println("instances.size():"+instances.size());

ServiceInstance serviceInstance = instances.get(new Random().nextInt(instances.size()));

URI uri = serviceInstance.getUri();

String str = this.restTemplate.getForObject(uri +"/user/list",String.class);

使用Ribbon

參考文件:https://cloud.spring.io/spring-cloud-netflix/reference/html/

參考文件-ribbon細節:https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html

概念

Ribbon是Netflix發佈的雲中間層服務開源專案,主要功能是提供用戶端(消費者方)負載均衡演算法。Ribbon用戶端元件提供一系列完善的設定項,如,連線超時,重試等。簡單的說,Ribbon是一個用戶端負載均衡器,我們可以在組態檔中列出load Balancer後面所有的機器,Ribbon會自動的幫助你基於某種規則(如簡單輪詢,隨機連線等)去連線這些機器,我們也很容易使用Ribbon實現自定義的負載均衡演算法。

Bean範例

The following table shows the beans that Spring Cloud Netflix provides by default for Ribbon:

Bean Type Bean Name Class Name 作用
IClientConfig ribbonClientConfig DefaultClientConfigImpl 讀取設定
IRule ribbonRule ZoneAvoidanceRule 負載均衡規則,選擇範例
IPing ribbonPing DummyPing 篩選掉ping不通的範例
ServerList<Server> ribbonServerList ConfigurationBasedServerList 交給Ribbon的範例列表
ServerListFilter<Server> ribbonServerListFilter ZonePreferenceServerListFilter 過濾掉不符合條件的範例
ILoadBalancer ribbonLoadBalancer ZoneAwareLoadBalancer Ribbon的入口
ServerListUpdater ribbonServerListUpdater PollingServerListUpdater 更新交給Ribbon的List的策略

開啓RestTemplate的負載均衡

  • 啓動類上新增@EnableDiscoveryClient
  • RestTemplate 範例新增 @LoadBalanced
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConsumerApplication {

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

程式碼實現自定義設定

區域性設定
@Configuration
@RibbonClient(name = "custom", configuration = CustomConfiguration.class)
public class TestConfiguration {
}

上面意思是,針對custom服務呼叫,選擇CustomConfiguration類的演算法合適

全域性設定
@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)

上面意思是,針對所有服務呼叫,選擇DefaultRibbonConfig類的演算法合適

注意

The CustomConfiguration class must be a @Configuration class, but take care that it is not in a @ComponentScan for the main application context. Otherwise, it is shared by all the @RibbonClients. If you use @ComponentScan (or @SpringBootApplication), you need to take steps to avoid it being included (for instance, you can put it in a separate, non-overlapping package or specify the packages to scan explicitly in the @ComponentScan).

需要將設定類放到@SpringBootApplication註解掃描不到的上級選單中,避免衝突

範例
  • @SpringBootApplication不可以掃描到的地方,定義一個Ribbon的設定類

    @Configuration
    public class RibbonConfig {
      @Bean
      public IRule getIRule(){
          return new BestAvailableRule();
      }
    }
    
  • @SpringBootApplication可以掃描到,定義一個Ribbon設定類,用來指定設定的位置

    @Configuration
    @RibbonClient(name = "custom", configuration = CustomConfiguration.class)
    public class TestConfiguration {
    }
    

properteis屬性設定自定義設定

Starting with version 1.2.0, Spring Cloud Netflix now supports customizing Ribbon clients by setting properties to be compatible with the Ribbon documentation.

This lets you change behavior at start up time in different environments.

The following list shows the supported properties>:

  • <clientName>.ribbon.NFLoadBalancerClassName: Should implement ILoadBalancer
  • <clientName>.ribbon.NFLoadBalancerRuleClassName: Should implement IRule
  • <clientName>.ribbon.NFLoadBalancerPingClassName: Should implement IPing
  • <clientName>.ribbon.NIWSServerListClassName: Should implement ServerList
  • <clientName>.ribbon.NIWSServerListFilterClassName: Should implement ServerListFilter
Classes defined in these properties have precedence over beans defined by using @RibbonClient(configuration=MyRibbonConfig.class) and the defaults provided by Spring Cloud Netflix.

To set the IRule for a service name called users, you could set the following properties:

application.yml

users:
  ribbon:
    NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule

See the Ribbon documentation for implementations provided by Ribbon.

與NacosServer聯動

可以通過在nacos server網頁上設定值,來動態調整Ribbon策略

  • 修改Ribbon的設定類,呼叫自定義的設定類

    @Configuration
    public class RibbonConfig {
    
        @Bean
        public IRule getIRule(){
            return new WeightRule;
        }
    }
    
  • 增加設定類

    public class WeightRule extends AbstractLoadBalancerRule {
    
        /**
         * 服務發現參數物件,Nacos自帶
         *
         * @date 2020/08/11
         * @see NacosDiscoveryProperties
         */
        @Resource
        private NacosDiscoveryProperties nacosDiscoveryProperties;
        /**
         * 設定初始化
         *
         * @param iClientConfig 我的用戶端設定
         * @return
         * @author Jiangmanman
         * @date 2020/08/11
         */
        @Override
        public void initWithNiwsConfig(IClientConfig iClientConfig) {
        }
    
        @SneakyThrows
        @Override
        public Server choose(Object key) {
            //1.拿到要存取的服務名
            //1.1呼叫父類別物件
            ILoadBalancer loadBalancer = this.getLoadBalancer();
            //1.2轉換成真正的實現類
            BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer)loadBalancer;
            //1.3得到載入的服務名稱
            String serviceName = baseLoadBalancer.getName();
            //2.通過服務名獲得在網頁端往 Nacos Service 設定的權重值的範例
            //2.1通過Nacos參數物件獲得服務名
            NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
            //2.1得到所有的健康的範例
            Instance instance = namingService.selectOneHealthyInstance(serviceName);
            return new NacosServer(instance);
        }
    }
    
    
  • 優化,可以限定上,僅呼叫相同叢集下的instance(或者更加精確)

            //優化,通過服務名在Nacos上面獲得相同叢集下面 下麪的instance
            //獲得服務名下所有健康的範例
            List<Instance> allInstances = namingService.getAllInstances(serviceName, true);
            //獲得當前叢集名
            String clusterName = nacosDiscoveryProperties.getClusterName();
            //進行比對
            List<Instance> clusterInstance = allInstances.stream().filter(instance1 -> {
                return Objects.equals(clusterName, instance1);
            }).collect(Collectors.toList());
            //判斷是否有相鄰的叢集節點
            if (CollectionUtils.isEmpty(clusterInstance)) {
                //維持原樣
                clusterInstance = allInstances;
            }
            //通過權重演算法從集閤中獲取一個instance,分析前面的 selectOneHealthyInstance 方法,裏面就有實現的過程
            Instance weightInstance = Mybalancer.getWeightInstance(clusterInstance);
    
    	/**
    	*這個類是分析 selectOneHealthyInstance 方法的實現得來的
    	*/
        public static class Mybalancer extends Balancer{
    
            public static   Instance getWeightInstance(List<Instance> hosts){
                return getHostByRandomWeight(hosts);
            }
        }
    
    

    注意:上述的優化只是手動實現,其實NamingService裏面的selectOneHealthyInstance方法的過載裏面有對這個的實現,直接呼叫即可

現在就可以通過Nacos Server 在網頁中手動設定權重值,動態改變呼叫者,但是遇到No instances available,原因是設定裏面進行了分組造成的,將分組去掉後可以正常呼叫,原因不明,有時間在回頭看

快取的設定

Ribbon第一次呼叫比較慢,就是因爲預設實現是懶載入的方式,呼叫後纔會取拉取資訊,可以通過設定來修改這種預設行爲

參考文件7.9

Each Ribbon named client has a corresponding child application Context that Spring Cloud maintains. This application context is lazily loaded on the first request to the named client. This lazy loading behavior can be changed to instead eagerly load these child application contexts at startup, by specifying the names of the Ribbon clients, as shown in the following example:

application.yml

ribbon:
  eager-load:
    enabled: true
    clients: client1, client2, client3

Feign

Spring官方參考文件

概念

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka, as well as Spring Cloud LoadBalancer to provide a load-balanced http client when using Feign.

主要解決用戶端呼叫問題

使用方式

  • 匯入依賴

    To include Feign in your project use the starter with group org.springframework.cloud and artifact id spring-cloud-starter-openfeign. See the Spring Cloud Project page for details on setting up your build system with the current Spring Cloud Release Train.

            <!--Spring Feign-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
    
  • 設定註解@EnableFeignClients,呼叫方必須設定,被呼叫方可以不設定

    @SpringBootApplication
    @EnableFeignClients
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    
    }
    
  • 編寫介面,介面的設定和要呼叫的controller保持一直

    @FeignClient("service-user")
    //呼叫的方法有,這裏也必須有,保證一致性
    @RequestMapping("/news")
    public interface UserClient {
        @GetMapping("/all")
        CommonResult all();
    }
    
  • 注意:

    • 使用註解@FeignClient的介面去呼叫其他服務一定要標準化,例如多個參數必須使用@RequestParam來註明
    • 在呼叫表單參數的方法時,例如CommonResult all(User user);,需要將物件轉變成表單參數,加上@SpringQueryMap註解

開啓日誌(預設關閉)

程式碼實現
  • 編寫設定類

    @Configuration
    public class FooConfiguration {
        @Bean
        Logger.Level feignLoggerLevel() {
            return Logger.Level.FULL;
        }
    }
    
  • 全域性設定需要在@EnableFeignClients註解上指定defaultConfiguration 屬性,例如:@EnableFeignClients(defaultConfiguration = UserClient.class)

  • 具備設定則是將@FeignClient("service-user")變成@FeignClient(name = "service-user",configuration = FeignConfig.class)

設定實現
  • 開啓整體的預設日誌環境,例如上訴UserClient類所在的的包

    logging:
      level: 
        com.jungle.servicenews.client: debug
    
  • 開啓日誌,還可以設定其他feign的屬性

    feign:
      client:
        config:
          #也可以針對某個包進行設定
          default:
            connectTimeout: 5000
            readTimeout: 5000
            #日誌級別:NONE(預設),BASIC,HEADERS,FULL
            loggerLevel: FULL
    

連線優化

因爲feign預設的是來一次就建立一次連線,可以設定類似連線池的東東

設定如下:

feign:
#  client:
#    config:
#      #也可以針對某個包進行設定
#      default:
#        connectTimeout: 5000
#        readTimeout: 5000
#        #日誌級別:NONE(預設),BASIC,HEADERS,FULL
#        loggerLevel: FULL
  httpclient:
    enabled: true
    max-connections: 200
    max-connections-per-route: 50
    connection-timeout: 200000

Sentinel

Github上的參考資料-簡要

Github上的參考資料-詳細

在github上搜尋spring-cloud-alibaba

  • 然後點選上面Wiki,進入的是每個模組下面 下麪大致的內容
  • 點選下面 下麪的read.me的內容,可以進入到具體的某個模組,再點選上面的wiki便可以進入這個模組的具體內容

在spring官網上的參考資料說明如下所示

[外連圖片轉存失敗,源站可能有防盜鏈機制 機製,建議將圖片儲存下來直接上傳(img-KkE3ZUXp-1597236593842)(https://s3.ap-northeast-1.wasabisys.com/img.tw511.com/202008/20200811195853oxqm5p5exhf.png)]

簡介

隨着微服務的流行,服務和服務之間的穩定性變得越來越重要。 Sentinel 以流量爲切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。

使用方式

  • 前置,通過actuator暴露端點資訊,先匯入依賴

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    
  • 然後修改組態檔,加入如下

    management:
      endpoints:
        web:
          exposure:
            #下面 下麪是暴漏所有端點
            include: "*"
    
  • 測試暴漏端點是否成功,開啓網頁存取:IP+埠+/actuator檢視所有暴漏的端點資訊,引入sentinel依賴後,可以直接通過IP:埠/actuator/sentinel存取檢視sentinel的資訊

  • 引入依賴,如果要在您的專案中引入 Sentinel,使用 group ID 爲 com.alibaba.cloud 和 artifact ID 爲 spring-cloud-starter-alibaba-sentinel 的 starter。

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    
  • 下載centinel控制檯,下載地址:https://download.csdn.net/download/qq_35742333/12705492,下載完成直接可以執行java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar,執行完成直接ip+埠存取,預設java -jar 啓動後的埠爲8080,預設賬戶密碼一致,都爲sentinel

  • 服務與控制檯建立通訊

      cloud:
        sentinel:
          transport:
            #控制檯與服務之間通訊的埠,不寫預設也會給個8719
            port: 8719
            #控制檯位置
            dashboard: localhost:8080
    
  • 測試:服務至少有一次存取,控制檯的網頁纔會有顯示

  • 對介面的呼叫如果出現返回數據爲XML格式,因爲sentinel中整合了com.fastxml.jackson.dataformat的jackson-dataformat-xml.xml優先順序比JSON高,所以先返回XML

    • 解決方式一,去除sentinel依賴包的com.fastxml.jackson-dataformat

              <dependency>
                  <groupId>com.alibaba.cloud</groupId>
                  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
                  <exclusions>
                      <exclusion>
                          <groupId>com.fasterxml.jackson.dataformat</groupId>
                          <artifactId>jackson-dataformat-xml</artifactId>
                      </exclusion>
                  </exclusions>
              </dependency>
      
    • 解決方式二,Controller層增加返回格式指定@GetMapping(value = "/all",produces = MediaType.APPLICATION_JSON_VALUE)

流量控制

控制模式
  • 直接
    • 針對資源自己直接進行流量控制
  • 關聯
    • 監控關聯資源的流量情況來對自身資源進行限制
  • 鏈路
    • 對資源內部呼叫的資源進行入口來源的限制
控制效果
  • 快速失敗
    • 達到閾值之後直接拋出異常
  • Warm Up
    • 當瀏覽在一瞬間很大的時候,不會讓流量立即到達閾值,而是經過一段時間慢慢的預熱增長
  • 排隊通過
    • 請求達到閾值進行

熔斷降級

  • 平均響應時間 (DEGRADE_GRADE_RT):當 1s 內持續進入 N 個請求,對應時刻的平均響應時間(秒級)均超過閾值(count,以 ms 爲單位),那麼在接下的時間視窗(DegradeRule 中的 timeWindow,以 s 爲單位)之內,對這個方法的呼叫都會自動地熔斷(拋出 DegradeException)。注意 Sentinel 預設統計的 RT 上限是 4900 ms,超出此閾值的都會算作 4900 ms,若需要變更此上限可以通過啓動設定項 -Dcsp.sentinel.statistic.max.rt=xxx 來設定。
  • 異常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):當資源的每秒請求量 >= N(可設定),並且每秒異常總數佔通過量的比值超過閾值(DegradeRule 中的 count)之後,資源進入降級狀態,即在接下的時間視窗(DegradeRule 中的 timeWindow,以 s 爲單位)之內,對這個方法的呼叫都會自動地返回。異常比率的閾值範圍是 [0.0, 1.0],代表 0% - 100%。
  • 異常數 (DEGRADE_GRADE_EXCEPTION_COUNT):當資源近 1 分鐘的異常數目超過閾值之後會進行熔斷。注意由於統計時間視窗是分鐘級別的,若 timeWindow 小於 60s,則結束熔斷狀態後仍可能再進入熔斷狀態。
  • 注意:設定異常比例時,時間視窗的時間應該大於或者等於60S,因爲假如設定30比例,時間視窗設定爲10S,那麼因爲預設的比例計算時間是60S統計一次,熔斷降級後10S內又呼叫,則還是會讀取到30S比例(寫的什麼毛線!)

熱點參數限流

Github上WIKI參考文件

在需要進行限流的方法上加上註解@SentinelResource("myMethod")

注意:若需要設定例外項或者使用叢集維度流控,則傳入的參數只支援基本型別。

如果還是測試不好

組態檔將filter幹掉

  cloud:
    #sentinel:
      #transport:
        #控制檯與服務之間通訊的埠,不寫預設也會給個8719
       # port: 8719
        #控制檯位置
        #dashboard: localhost:8080
      filter:
        enabled: false

PS:感覺熱點參數限流這裏測試沒成功。。。QAQ

擴充套件介面

Github參考文件

下表顯示當應用的 ApplicationContext 中存在對應的Bean的型別時,會進行自動化設定:

存在Bean的型別 操作 作用
UrlCleaner WebCallbackManager.setUrlCleaner(urlCleaner) 資源清理(資源(比如將滿足 /foo/:id 的 URL 都歸到 /foo/* 資源下))
UrlBlockHandler WebCallbackManager.setUrlBlockHandler(urlBlockHandler) 自定義限流處理邏輯
RequestOriginParser WebCallbackManager.setRequestOriginParser(requestOriginParser) 設定來源資訊

Spring Cloud Alibaba Sentinel 提供了這些設定選項:

設定項 含義 預設值
spring.application.name or project.name Sentinel專案名
spring.cloud.sentinel.enabled Sentinel自動化設定是否生效 true
spring.cloud.sentinel.eager 是否提前觸發 Sentinel 初始化 false
spring.cloud.sentinel.transport.port 應用與Sentinel控制檯互動的埠,應用本地會起一個該埠佔用的HttpServer 8719
spring.cloud.sentinel.transport.dashboard Sentinel 控制檯地址
spring.cloud.sentinel.transport.heartbeat-interval-ms 應用與Sentinel控制檯的心跳間隔時間
spring.cloud.sentinel.transport.client-ip 此設定的用戶端IP將被註冊到 Sentinel Server 端
spring.cloud.sentinel.filter.order Servlet Filter的載入順序。Starter內部會構造這個filter Integer.MIN_VALUE
spring.cloud.sentinel.filter.url-patterns 數據型別是陣列。表示Servlet Filter的url pattern集合 /*
spring.cloud.sentinel.filter.enabled Enable to instance CommonFilter true
spring.cloud.sentinel.metric.charset metric檔案字元集 UTF-8
spring.cloud.sentinel.metric.file-single-size Sentinel metric 單個檔案的大小
spring.cloud.sentinel.metric.file-total-count Sentinel metric 總檔案數量
spring.cloud.sentinel.log.dir Sentinel 日誌檔案所在的目錄
spring.cloud.sentinel.log.switch-pid Sentinel 日誌檔名是否需要帶上 pid false
spring.cloud.sentinel.servlet.block-page 自定義的跳轉 URL,當請求被限流時會自動跳轉至設定好的 URL
spring.cloud.sentinel.flow.cold-factor WarmUp 模式中的 冷啓動因子 3
spring.cloud.sentinel.zuul.order.pre SentinelZuulPreFilter 的 order 10000
spring.cloud.sentinel.zuul.order.post SentinelZuulPostFilter 的 order 1000
spring.cloud.sentinel.zuul.order.error SentinelZuulErrorFilter 的 order -1
spring.cloud.sentinel.scg.fallback.mode Spring Cloud Gateway 流控處理邏輯 (選擇 redirect or response)
spring.cloud.sentinel.scg.fallback.redirect Spring Cloud Gateway 響應模式爲 ‘redirect’ 模式對應的重定向 URL
spring.cloud.sentinel.scg.fallback.response-body Spring Cloud Gateway 響應模式爲 ‘response’ 模式對應的響應內容
spring.cloud.sentinel.scg.fallback.response-status Spring Cloud Gateway 響應模式爲 ‘response’ 模式對應的響應碼 429
spring.cloud.sentinel.scg.fallback.content-type Spring Cloud Gateway 響應模式爲 ‘response’ 模式對應的 content-type application/json
Note 請注意。這些設定只有在 Servlet 環境下纔會生效,RestTemplate 和 Feign 針對這些設定都無法生效

範例:

修改存取URL
  //可以修改存取的URL
  @Component
  public class MyUrlCleaner implements UrlCleaner {
  
      @Override
      public String clean(String s) {
  
          System.out.println(s);
          //修改來源的URL
          return s+":admin";
      }
  }
自定義流控返回(加了@SentinelResource註解後,這個就不會生效)
  @Component
  public class MyUrlBlockHandler implements BlockExceptionHandler {
      @Override
      public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
  
          response.setContentType("application/json;charset=utf8");
          response.setCharacterEncoding("utf-8");
          response.getWriter().write("{\"msg\":\"流控\"}");
          response.getWriter().flush();
      }
  }
設定來源資訊

和上一樣,只改變實現介面RequestOriginParser,可以通過request.getParameter得到請求攜帶的參數

註解支援

Github上詳細參考

@SentinelResource 註解

注意:註解方式埋點不支援 private 方法。

@SentinelResource 用於定義資源,並提供可選的例外處理和 fallback 設定項。 @SentinelResource 註解包含以下屬性:

  • value:資源名稱,必需項(不能爲空)
  • entryType:entry 型別,可選項(預設爲 EntryType.OUT
  • blockHandler / blockHandlerClass: blockHandler 對應處理 BlockException 的函數名稱,可選項。blockHandler 函數存取範圍需要是 public,返回型別需要與原方法相匹配,參數型別需要和原方法相匹配並且最後加一個額外的參數,型別爲 BlockException。blockHandler 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 blockHandlerClass 爲對應的類的 Class 物件,注意對應的函數必需爲 static 函數,否則無法解析。
  • fallback / fallbackClass:fallback 函數名稱,可選項,用於在拋出異常的時候提供 fallback 處理邏輯。fallback 函數可以針對所有型別的異常(除了 exceptionsToIgnore 裏面排除掉的異常型別)進行處理。fallback 函數簽名和位置要求:
    • 返回值型別必須與原函數返回值型別一致;
    • 方法參數列表需要和原函數一致,或者可以額外多一個 Throwable 型別的參數用於接收對應的異常。
    • fallback 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 fallbackClass 爲對應的類的 Class 物件,注意對應的函數必需爲 static 函數,否則無法解析。
  • defaultFallback(since 1.6.0):預設的 fallback 函數名稱,可選項,通常用於通用的 fallback 邏輯(即可以用於很多服務或方法)。預設 fallback 函數可以針對所有型別的異常(除了 exceptionsToIgnore裏面排除掉的異常型別)進行處理。若同時設定了 fallback 和 defaultFallback,則只有 fallback 會生效。defaultFallback 函數簽名要求:
    • 返回值型別必須與原函數返回值型別一致;
    • 方法參數列表需要爲空,或者可以額外多一個 Throwable 型別的參數用於接收對應的異常。
    • defaultFallback 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 fallbackClass 爲對應的類的 Class 物件,注意對應的函數必需爲 static 函數,否則無法解析。
  • exceptionsToIgnore(since 1.6.0):用於指定哪些異常被排除掉,不會計入異常統計中,也不會進入 fallback 邏輯中,而是會原樣拋出。

注:1.6.0 之前的版本 fallback 函數只針對降級異常(DegradeException)進行處理,不能針對業務異常進行處理

特別地,若 blockHandler 和 fallback 都進行了設定,則被限流降級而拋出 BlockException 時只會進入 blockHandler 處理邏輯。若未設定 blockHandlerfallbackdefaultFallback,則被限流降級時會將 BlockException 直接拋出(若方法本身未定義 throws BlockException 則會被 JVM 包裝一層 UndeclaredThrowableException)。

範例:

public class TestService {

    // 對應的 `handleException` 函數需要位於 `ExceptionUtil` 類中,並且必須爲 static 函數.
    @SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
    public void test() {
        System.out.println("Test");
    }

    // 原函數
    @SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")
    public String hello(long s) {
        return String.format("Hello at %d", s);
    }
    
    // Fallback 函數,函數簽名與原函數一致或加一個 Throwable 型別的參數.
    public String helloFallback(long s) {
        return String.format("Halooooo %d", s);
    }

    // Block 例外處理函數,參數最後多一個 BlockException,其餘與原函數一致.
    public String exceptionHandler(long s, BlockException ex) {
        // Do some log here.
        ex.printStackTrace();
        return "Oops, error occurred at " + s;
    }
}

從 1.4.0 版本開始,註解方式定義資源支援自動統計業務異常,無需手動呼叫 Tracer.trace(ex) 來記錄業務異常。Sentinel 1.4.0 以前的版本需要自行呼叫 Tracer.trace(ex) 來記錄業務異常。

設定
Spring Cloud Alibaba

若您是通過 Spring Cloud Alibaba 接入的 Sentinel,則無需額外進行設定即可使用 @SentinelResource 註解。

Spring AOP

若您的應用使用了 Spring AOP(無論是 Spring Boot 還是傳統 Spring 應用),您需要通過設定的方式將 SentinelResourceAspect 註冊爲一個 Spring Bean:

@Configuration
public class SentinelAspectConfiguration {

    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }
}

我們提供了 Spring AOP 的範例,可以參見 sentinel-demo-annotation-spring-aop

AspectJ

若您的應用直接使用了 AspectJ,那麼您需要在 aop.xml 檔案中引入對應的 Aspect:

<aspects>
    <aspect name="com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect"/>
</aspects>
Feign的支援

Sentinel 適配了 Feign 元件。如果想使用,除了引入 spring-cloud-starter-alibaba-sentinel 的依賴外還需要 2 個步驟:

  • 組態檔開啓 Sentinel 對 Feign 的支援:feign.sentinel.enabled=true
  • 加入 spring-cloud-starter-openfeign 依賴使 Sentinel starter 中的自動化設定類生效:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

這是一個 FeignClient 的簡單使用範例:

@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
public interface EchoService {
    @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
    String echo(@PathVariable("str") String str);
}

class FeignConfiguration {
    @Bean
    public EchoServiceFallback echoServiceFallback() {
        return new EchoServiceFallback();
    }
}

class EchoServiceFallback implements EchoService {
    @Override
    public String echo(@PathVariable("str") String str) {
        return "echo fallback";
    }
}
RestTemplate的支援

Spring Cloud Alibaba Sentinel 支援對 RestTemplate 的服務呼叫使用 Sentinel 進行保護,在構造 RestTemplate bean的時候需要加上 @SentinelRestTemplate 註解。

@Bean
@SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
public RestTemplate restTemplate() {
    return new RestTemplate();
}

@SentinelRestTemplate 註解的屬性支援限流(blockHandler, blockHandlerClass)和降級(fallback, fallbackClass)的處理。

其中 blockHandlerfallback 屬性對應的方法必須是對應 blockHandlerClassfallbackClass 屬性中的靜態方法。

該方法的參數跟返回值跟 org.springframework.http.client.ClientHttpRequestInterceptor#interceptor 方法一致,其中參數多出了一個 BlockException 參數用於獲取 Sentinel 捕獲的異常。

比如上述 @SentinelRestTemplate 註解中 ExceptionUtilhandleException 屬性對應的方法宣告如下:

public class ExceptionUtil {
    public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) {
        ...
    }
}
Note 應用啓動的時候會檢查 @SentinelRestTemplate 註解對應的限流或降級方法是否存在,如不存在會拋出異常

@SentinelRestTemplate 註解的限流(blockHandler, blockHandlerClass)和降級(fallback, fallbackClass)屬性不強制填寫。

當使用 RestTemplate 呼叫被 Sentinel 熔斷後,會返回 RestTemplate request block by sentinel 資訊,或者也可以編寫對應的方法自行處理返回資訊。這裏提供了 SentinelClientHttpResponse 用於構造返回資訊。

Sentinel RestTemplate 限流的資源規則提供兩種粒度:

  • httpmethod:schema://host:port/path:協定、主機、埠和路徑
  • httpmethod:schema://host:port:協定、主機和埠
Note https://www.taobao.com/test 這個 url 並使用 GET 方法爲例。對應的資源名有兩種粒度,分別是 GET:https://www.taobao.com 以及 GET:https://www.taobao.com/test

Spring Cloud Gateway

Spring官網參考資料

概念

To include Spring Cloud Gateway in your project, use the starter with a group ID of org.springframework.cloud and an artifact ID of spring-cloud-starter-gateway. See the Spring Cloud Project page for details on setting up your build system with the current Spring Cloud Release Train.

If you include the starter, but you do not want the gateway to be enabled, set spring.cloud.gateway.enabled=false.

Spring Cloud Gateway is built on Spring Boot 2.x, Spring WebFlux, and Project Reactor. As a consequence, many of the familiar synchronous libraries (Spring Data and Spring Security, for example) and patterns you know may not apply when you use Spring Cloud Gateway. If you are unfamiliar with these projects, we suggest you begin by reading their documentation to familiarize yourself with some of the new concepts before working with Spring Cloud Gateway.
Spring Cloud Gateway requires the Netty runtime provided by Spring Boot and Spring Webflux. It does not work in a traditional Servlet Container or when built as a WAR.

大致就是如何使用,以及注意gateeay不是傳統的springweb專案,所以不要匯入亂七八糟的web包

使用方式

首先導包

  • 因爲閘道器也需要註冊到Nacos裏面去,所以需要匯入Nacos的包

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
    
  • Nacos爲啥不要寫版本號,因爲交給dependencyManagement標籤來管理了,所以需要匯入

        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>com.alibaba.cloud</groupId>
                    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                    <version>2.2.1.RELEASE</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
  • 匯入閘道器自身的包spring.cloud.gateway,然後依賴於springboot以及自身受dependencyManagement裏面的rg.springframework.cloud來管理自身的版本,所以這裏直接給出完整的pom設定,Jiang慢慢應該懂得

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.1.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.jungle.gateway</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>demo</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
    
    
    
        </dependencies>
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Hoxton.SR6</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <dependency>
                    <groupId>com.alibaba.cloud</groupId>
                    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                    <version>2.2.1.RELEASE</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    
    • 將網關注冊到Nacos Server裏面,以及開啓Gateway,設定如下

      spring:
        cloud:
          gateway:
            #開啓閘道器的自動路由方式,也就是通過url的服務名稱去找到對應的服務
            discovery:
              locator:
                enabled: true
          nacos:
            discovery:
              #        #命令空間ID
              namespace: d2f4bb90-17ac-4bc1-9e32-8734e722eb0c
              #        #叢集
              cluster-name: newMachine
            #        group: 1
            #        metadata:
            #          testKey1: testValue1
            #          testKey2: testValue2
            server-addr: 127.0.0.1:8848
      server:
        port: 9001
      
      
    • 啓動報錯org.springframework.cloud.gateway.config.GatewayAutoConfiguration$NettyConfiguration.gatewayHttpClient(GatewayAutoConfiguration.java:622),反正是依賴有問題,直接ctrl+左鍵點選gateway的依賴,檢視這個吊毛到底要毛線依賴,發現依賴的是2.3.0的springboot版本,改了下,ok,然後通過IP:9001/服務名/news/testTemplate測試成功

自定義設定

最有用的是謂詞工廠,可以通過這個來指定什麼請求什麼時間段存取什麼服務

server:
  port: 9001
spring:
  application:
    name: spring-cloud-gateway
  cloud:
    gateway:
      enabled: true
      routes:
        # 自定義唯一標識
        - id: damkdamk54da1
          # 呼叫自己服務可以使用:lb://服務名
          # uri: http://baidu.com
          uri: lb://service-news
          predicates:
            #謂詞工廠,例如這裏針對COOKIE名爲mycookie,值爲mycookieValue的到上面的uri中
            #使用最多的是 - Path
            - Path=/news/**
        - id: httpbin_route
          uri: https://httpbin.org
          predicates:
            - Path=/httpbin/**
    nacos:
      discovery:
        #        #命令空間ID
        namespace: d2f4bb90-17ac-4bc1-9e32-8734e722eb0c
        #        #叢集
        cluster-name: newMachine
      #        group: 1
      #        metadata:
      #          testKey1: testValue1
      #          testKey2: testValue2
      server-addr: 127.0.0.1:8848


Filter的使用

區域性設定可以在組態檔中使用,也就是在routes下面 下麪增加

          filters:
            - RewritePath=/httpbin/(?<segment>.*), /$\{segment}

全域性的寫出來丟到容器中,或者在組態檔中gateway的下面 下麪增加default-filter也可以

自定義Filter

!!!注意:攔截器弄好了千萬記得加@Component註解放到容器中,這是我弄完Filter後得到的經驗教訓

  • 可以模仿SpringCloudGateway的實現自己來寫一個,例如在idea中使用ctrl+N搜尋類AddRequestHeaderGatewayFilterFactory

  • 實現過程如下

  • 可以看出AddRequestHeaderGatewayFilterFactory類繼承了 extends AbstractAuthenticationGatewayFilterFactory抽象類,並且重寫了一個apply方法.那麼可以自建一個類,保持名字的一致性,就是自定義名+GatewayFilterFactory這種格式,這種格式可以直接在設定中給每個服務區域性設定

    package com.jungle.gateway.demo.filter;
    
    import org.apache.commons.lang.StringUtils;
    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory;
    import org.springframework.cloud.gateway.support.GatewayToStringStyler;
    import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    /**
     * @author Jiangmanman
     */
    @Component
    public class AuthenticationGatewayFilterFactory extends AbstractAuthenticationGatewayFilterFactory{
    
    
    
        @Override
        public GatewayFilter apply(Config config) {
    
            return new GatewayFilter() {
    
                @Override
                public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                    ServerHttpRequest request = exchange.getRequest();
                    System.out.println("/******************進入認證過濾器**********************/");
                    System.out.println("/******************取出參數"+config+"**********************/");
                    String token = request.getHeaders().getFirst("token");
                    System.out.println(request.getHeaders());
                    if(StringUtils.isBlank(token)){
                        throw new RuntimeException("沒有Token");
                    }
    
    
                    return chain.filter(exchange);
                }
    
                @Override
                public String toString() {
                    return GatewayToStringStyler.filterToStringCreator(AuthenticationGatewayFilterFactory.this).append(config.getName()).toString();
                }
    
    
            };
        }
    }
    
    
  • 抽象類AbstractAuthenticationGatewayFilterFactory繼承了AbstractGatewayFilterFactory這個介面,並且指定了由哪個類去讀取參數,shortcutFieldOrder方法主要用來控制參數的排序

    package com.jungle.gateway.demo.filter;
    
    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
    import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
    import org.springframework.core.style.ToStringCreator;
    import org.springframework.validation.annotation.Validated;
    
    import javax.validation.constraints.NotEmpty;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    
    /**
     * @author Jiangmanman
     */
    public abstract class AbstractAuthenticationGatewayFilterFactory  extends AbstractGatewayFilterFactory<AbstractAuthenticationGatewayFilterFactory.Config> {
    
    
        public AbstractAuthenticationGatewayFilterFactory() {
            super(AbstractAuthenticationGatewayFilterFactory.Config.class);
        }
    
        @Override
        public List<String> shortcutFieldOrder() {
            return Collections.singletonList("name");
        }
    
        @Validated
        public static class Config {
            @NotEmpty
            protected String name;
    
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            @Override
            public String toString() {
                return "NameValueConfig{" +
                        "name='" + name + '\'' +
                        '}';
            }
            public String getValue() {
                return this.name;
            }
    
    
        }
    
    }
    
    

最後在在設定上寫上服務對應的過濾器名即可,如下所示,增加的就是最後一行

spring:
  application:
    name: spring-cloud-gateway
  cloud:
    gateway:
      enabled: true
      routes:
        # 自定義唯一標識
        - id: damkdamk54da1
          # 呼叫自己服務可以使用:lb://服務名
          # uri: http://baidu.com
          uri: lb://service-news
          predicates:
            #謂詞工廠,例如這裏針對COOKIE名爲mycookie,值爲mycookieValue的到上面的uri中
            #使用最多的是 - Path
            - Path=/news/**
          filters:
            - Authentication=test

上面的自定義Filter主要用來做服務的區域性設定,對於服務的全域性設定(攔截所有服務)程式碼實現如下

@Component
public class MyglobalFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        System.out.println("=========全域性攔截===========");

        return chain.filter(exchange);
    }
}
過濾器順序

spring官方網站7.1裡就有實現方法,就是通過實現Ordered介面再重寫getOrder方法,給一個值,越小的值,優先順序越高,越大的值優先順序越低

hen a request matches a route, the filtering web handler adds all instances of GlobalFilter and all route-specific instances of GatewayFilter to a filter chain. This combined filter chain is sorted by the org.springframework.core.Ordered interface, which you can set by implementing the getOrder() method.

As Spring Cloud Gateway distinguishes between 「pre」 and 「post」 phases for filter logic execution (see How it Works), the filter with the highest precedence is the first in the 「pre」-phase and the last in the 「post」-phase.

The following listing configures a filter chain:

Example 59. ExampleConfiguration.java

@Bean
public GlobalFilter customFilter() {
    return new CustomGlobalFilter();
}

public class CustomGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("custom global filter");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

爲了測試這個改變Filter攔截的順序,我又把Filter提取出去了,不然怎麼實現Ordered介面呢…,如下所示

public class MyServiceFilter  implements GatewayFilter, Ordered {

    private AbstractAuthenticationGatewayFilterFactory.Config config;

    public MyServiceFilter() {
    }

    public MyServiceFilter(AbstractAuthenticationGatewayFilterFactory.Config config) {
        this.config = config;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        System.out.println("/******************進入認證過濾器**********************/");
        System.out.println("/******************取出參數"+config+"**********************/");
        String token = request.getHeaders().getFirst("token");
        System.out.println(request.getHeaders());
        if(StringUtils.isBlank(token)){
            throw new RuntimeException("沒有Token");
        }


        return chain.filter(exchange);
    }

    @Override
    public String toString() {
        return GatewayToStringStyler.filterToStringCreator(MyServiceFilter.this).append(config.getName()).toString();
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
@Component
public class AuthenticationGatewayFilterFactory extends AbstractAuthenticationGatewayFilterFactory{

    @Override
    public GatewayFilter apply(Config config) {

        return new MyServiceFilter();
    }
}
filter在請求從服務返回後進行處理

參考資料17.2

在上面MyServiceFilter類裡的filter方法

        return chain.filter(exchange).then(Mono.fromRunnable(()->{
            // 請求-》過濾器-》服務-》過濾器(現在在這裏)-》返回請求
            //例如可以計算這次服務的響應時間
        }));
Http超時設定

參考資料12

Http timeouts (response and connect) can be configured for all routes and overridden for each specific route.

Global timeouts

To configure Global http timeouts:
connect-timeout must be specified in milliseconds.
response-timeout must be specified as a java.time.Duration

global http timeouts example

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 1000
        response-timeout: 5s
Per-route timeouts

To configure per-route timeouts:
connect-timeout must be specified in milliseconds.
response-timeout must be specified in milliseconds.

per-route http timeouts configuration via configuration

      - id: per_route_timeouts
        uri: https://example.org
        predicates:
          - name: Path
            args:
              pattern: /delay/{timeout}
        metadata:
          response-timeout: 200
          connect-timeout: 200

專案檔案

專案檔案:鏈接: https://pan.baidu.com/s/1N4eMWDfjzQZwoWwusYwoZA 提取碼: at59

將組態檔中的數據庫連線去掉即可執行,加上Nacos Server可正常註冊,加上Sentinel可正常進行服務流控和降級