主頁 > 軟體設計 > SpringCloud 學習總結(二)

SpringCloud 學習總結(二)

2020-12-13 12:20:58 軟體設計

  • SpringCloud 學習總結(一)
  • SpringCloud 學習總結(二)

服務容錯保護Hystrix

Hystix是Netflix開源的一個延遲和容錯庫,其中提供了基礎的熔斷功能,用于隔離訪問遠程服務、第三方庫,防止出現級聯失敗,關于Hystrix更詳細的原理,可以參考官方檔案:https://github.com/Netflix/Hystrix/

在這里插入圖片描述

雪崩問題: 在微服務框架中,系統間都通過微服務進行呼叫,在微服務之間會存在這相互依賴關系,假設每個微服務運行在不同的行程中,依賴的呼叫只則需要使用遠程呼叫方式,如果其中一個網路出現問題,或者延遲,此時,呼叫方式在不斷的呼叫,后方的依賴會出現故障,當回應過多時,就可能出現雪崩效應,造成系統的崩潰,

下圖中,我們可以看到微服務中,服務間復雜的呼叫關系,一個請求,可能需要呼叫多個微服務介面才能實作,會形成非常復雜的呼叫鏈路:

在這里插入圖片描述

如圖,一次業務請求,需要呼叫A、P、H、I四個服務,這四個服務又可能呼叫其它服務,如果此時,某個服務出現例外:

在這里插入圖片描述

例如:微服務I發生例外,請求阻塞,用戶不會得到回應,則tomcat的這個執行緒不會釋放,于是越來越多的用戶請求到來,越來越多的執行緒會阻塞:
在這里插入圖片描述

服務器支持的執行緒和并發數有限,請求一直阻塞,會導致服務器資源耗盡,從而導致所有其它服務都不可用,形成雪崩效應,

Hystix解決雪崩問題:

  • 執行緒隔離(服務降級)
  • 服務熔斷

服務降級

服務降級: 當系統的訪問量突然特別大時,因為資源有限,不可能提供全部服務的時候,優先保證核心服務,非核心服務不可用或者弱可用,

在Hystrix中也提供了服務降級的機制,Hystrix為每個依賴服務呼叫分配一個小的執行緒池,如果執行緒池已滿呼叫將被立即拒絕,默認不采用排隊,加速失敗判定時間,用戶的請求將不再直接訪問服務,而是通過執行緒池中的空閑執行緒來訪問服務,如果執行緒池已滿,或者請求超時,則會進行降級處理,

通過服務降級,用戶的請求故障時,不會被阻塞,更不會無休止的等待或者看到系統崩潰,至少可以看到一個執行結果(例如回傳友好的提示資訊),服務降級雖然會導致請求失敗,但是不會導致阻塞,而且最多會影響這個依賴服務對應的執行緒池中的資源,對其它服務沒有回應,

觸發Hystix服務降級的情況:

  • 執行緒池已滿
  • 請求超時

Hystrix將降級策略封裝在Commend中,不同的Commend根據group分割開,Commend內置了run和fallback兩個方法,內置方法,正常情況下,會先執行run方法(正常執行邏輯),若發生了故障,再執行fallback方法并回傳其結果,若發生多次故障會在一定時間范圍內觸發短路,即跳過run方法,直接執行fallback方法,

在程式中測驗Hystrix:

引入依賴:首先在springboot-service-consumer的pom.xml中引入Hystrix依賴:

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

修改啟動器的代碼:添加開啟熔斷注解:@EnableCircuitBreaker

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker   //開啟熔斷
public class SpringbootServiceConsumerApplication {
		、、、、
}

組合注解:@SpringCloudApplication,相當于@SpringBootApplication + @EnableDiscoveryClient + @EnableCircuitBreaker,可以用來簡化我們的注解:
在這里插入圖片描述

使用組合注解代替之前的3個注解:

@SpringCloudApplication //組合注解,相當于@SpringBootApplication + @EnableDiscoveryClient + @EnableCircuitBreaker
public class SpringbootServiceConsumerApplication {

    @Bean
    @LoadBalanced  //開啟負載均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringbootServiceConsumerApplication.class, args);
    }

}

撰寫降級邏輯:

改造springboot-service-consumer,當目標服務的呼叫出現故障,我們希望快速失敗,給用戶一個友好提示,因此需要提前撰寫好失敗時的降級處理邏輯,要使用@HystixCommond來完成:

@RestController
@RequestMapping("consumer/user")
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

	@GetMapping
    @HystrixCommand(fallbackMethod = "queryUserByIdFallback")  //宣告熔斷(降級邏輯)的方法
    public String queryUserById(@RequestParam("id") Long id) {
        return this.restTemplate.getForObject("http://service-provider/user/" + id, String.class);
    }
    
    public String queryUserByIdFallBack(Long id){
        return "請求繁忙,請稍后再試!";
    }
   
}

注意:熔斷的降級邏輯方法必須跟正常邏輯方法保證:相同的引數串列和回傳值宣告,失敗邏輯中回傳User物件沒有太大意義,一般會回傳友好提示,所以我們把queryById的方法改造為回傳String,反正也是Json資料,這樣失敗邏輯中回傳一個錯誤說明,會比較方便,

運行測驗:

當springboot-service-provder正常提供服務時
在這里插入圖片描述

將springboot-service-provider停機時,會發現頁面回傳了降級處理資訊:

在這里插入圖片描述

指定全域熔斷的熔斷方法:

區域:(要和被熔斷的方法回傳值和引數串列一致)
@HystrixCommand(fallbackMethod=“區域熔斷方法名”):宣告被熔斷的方法

全域:(回傳值型別要被熔斷的方法一致,引數串列必須為空)
@DefaultProperties(defaultFallback = “defaultFallBack”):在類上指明統一的失敗降級方法
defaultFallback:默認降級方法,不用任何引數,以匹配更多方法,但是回傳值一定一致
@HystrixCommand:在方法上直接使用該注解,使用默認的剪輯方法,

優先級:區域>全域

我們剛才把fallback寫在了某個業務方法上,如果這樣的方法很多,那豈不是要寫很多,所以我們可以把Fallback配置加在類上,實作默認fallback:

@RestController
@RequestMapping("consumer/user")
@DefaultProperties(defaultFallback = "fallBackMethod") // 指定一個類的全域熔斷方法
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping
    @HystrixCommand // 標記該方法需要熔斷
    public String queryUserById(@RequestParam("id") Long id) {
        String user = this.restTemplate.getForObject("http://service-provider/user/" + id, String.class);
        return user;
    }

    /**
     * 熔斷方法
     * 回傳值要和被熔斷的方法的回傳值一致
     * 熔斷方法不需要引數
     * @return
     */
    public String fallBackMethod(){
        return "服務器正忙,請稍后再試!";
    }
}

在這里插入圖片描述

設定超時

在微服務中,由于網路或者運算量等問題,超時是很常見的,Hystix中的默認超時時長為1,在互聯網中,有些服務需要訪問第三方應用,或者處理大量的資料,使用默認的1秒很容易超時,這時需要問們進行超時設定,通過hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds可以設定Hystrix超時時間,該配置沒有提示:

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000 # 設定hystrix的超時時間為6000ms

改造服務提供者

改造服務提供者的UserController介面,隨機休眠一段時間,以觸發熔斷:

@GetMapping("{id}")
public User queryUserById(@PathVariable("id") Long id) {
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return this.userService.queryUserById(id);
}

運行查看結果:
在這里插入圖片描述

服務熔斷

熔斷原理:熔斷器(斷路器),當某些服務反應慢或者存在大量超時問題時,服務呼叫方可以自己進行判斷,并進行熔斷,防止整個系統被拖垮,當情況好轉時,在進行自動重連,

通過斷路器的方式,可以將后續請求直接拒絕掉,一段時間之后允許部分請求通過,如果呼叫成功則回到電路閉合狀態,否則繼續斷開,

熔斷狀態機3個狀態:

  • Closed:關閉狀態,所有請求都正常訪問,
  • Open:打開狀態,所有請求都會被降級,Hystix會對請求情況計數,當一定時間內失敗請求百分比達到閾值,則觸發熔斷,斷路器會完全打開,默認失敗比例的閾值是50%,請求次數最少不低于20次,
  • Half Open:半開狀態,open狀態不是永久的,打開后會進入休眠時間(默認是5S),隨后斷路器會自動進入半開狀態,此時會釋放部分請求通過,若這些請求都是健康的,則會完全關閉斷路器,否則繼續保持打開,再次進行休眠計時

在程式中測驗:

在consumer的呼叫業務中加入一段邏輯:

@GetMapping
@HystrixCommand(fallbackMethod = "queryUserByIdFallback")  //宣告熔斷的方法
public String queryUserById(@RequestParam("id") Long id) {
    if(id==1){
        throw new RuntimeException();
    }
    return this.restTemplate.getForObject("http://service-provider/user/" + id, String.class);
}

這樣如果引數是id為1,一定失敗,其它情況都成功,(不要忘了清空service-provider中的休眠邏輯)

當我們連續訪問id為1的請求時(超過20次,手速要快),就會觸發熔斷,斷路器會斷開,一切請求都會被降級處理,此時你訪問id為2的請求,會發現回傳的也是失敗,而且失敗時間很短,只有幾毫秒左右:

第一次訪問id=2:
在這里插入圖片描述
連續訪問id=1:
在這里插入圖片描述
再次訪問id=2:
在這里插入圖片描述

不過,默認的熔斷觸發要求較高,休眠時間窗較短,為了測驗方便,我們可以通過配置修改熔斷策略:

circuitBreaker:
	requestVolumeThreshold: 10   #觸發熔斷的最小請求次數,默認20
	sleepWindowInMilliseconds: 10000   #觸發熔斷的失敗請求最小占比,默認50%
	errorThresholdPercentage: 50    #休眠時長,默認是5000毫秒

宣告式服務呼叫Feign

Feign是Netfix開發的宣告式、模板化的HTTP客戶端,它可幫助我們更加快捷的呼叫HTTP API,其中支持自帶的注解,JAX-Rs注解,SpringMVC注解,并且還整合了Ribbon與Eureka,通過使用Feign可以把Rest的請求進行隱藏,偽裝成類似SpringMVC的Controller一樣,你不用再自己拼接url,拼接引數等等操作,一切都交給Feign去做,十分方便,

Feign專案地址:https://github.com/OpenFeign/feign

在前面的學習中,我們使用了Ribbon的負載均衡功能,大大簡化了遠程呼叫時的代碼:

String user = this.restTemplate.getForObject("http://service-provider/user/" + id, String.class);

快速入門:

改造springboot-service-consumer工程:

在這里插入圖片描述

匯入依賴:

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

開啟Feign功能:在啟動類上,添加注解@EnableFeignClients開啟Feign功能

@SpringCloudApplication //組合注解,相當于@SpringBootApplication + @EnableDiscoveryClient + @EnableCircuitBreaker
@EnableFeignClients     //啟用feign組件
public class SpringbootServiceConsumerApplication {

    /*@Bean
    @LoadBalanced  //開啟負載均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }*/

    public static void main(String[] args) {
        SpringApplication.run(SpringbootServiceConsumerApplication.class, args);
    }

}

洗掉RestTemplate:feign已經自動集成了Ribbon負載均衡的RestTemplate,所以,此處不需要再注冊RestTemplate,

配置Feign的客戶端:

在springboot-service-consumer工程中,添加UserClient介面:

//@FeignClient(value = "service-provider") // 標注該類是一個feign介面
@FeignClient(value = "service-provider",fallback = UserClientFallBack.class)
public interface UserClient {

    @GetMapping("user/{id}")
    User queryById(@PathVariable("id") Long id);
}
  • 首先這是一個介面,Feign會通過動態代理,幫我們生成實作類,這點跟mybatis的mapper很像
  • @FeignClient,宣告這是一個Feign客戶端,類似@Mapper注解,同時通過value屬性指定服務名稱
  • 介面中的定義方法,完全采用SpringMVC的注解,Feign會根據注解幫我們生成URL,并訪問獲取結果

改造原來的呼叫邏輯,呼叫UserClient介面:

@RestController
@RequestMapping("consumer/user")
public class UserController {

    @Autowired
    private UserClient userClient;

    @GetMapping
    public String queryUserById(@RequestParam("id") Long id){
        User user = this.userClient.queryUserById(id);
        return user.toString();
    }

}

啟動測驗:

訪問介面:
在這里插入圖片描述
正常獲取到了結果,

負載均衡與Hystrix支持:

Feign中本身已經集成了Ribbon依賴和自動配置,因此我們不需要額外引入依賴,也不需要再注冊RestTemplate物件,

同時Feign默認也有對Hystrix的集成,只不過,默認情況下是關閉的,我們需要通過下面的引數來開啟:(在springboot-service-consumer工程添加配置內容):

feign:
  hystrix:
    enabled: true # 開啟Feign的熔斷功能

但是,Feign中的Fallback配置不像hystrix中那樣簡單了,首先,我們要定義一個類UserClientFallback,實作剛才撰寫的UserClient,作為fallback的處理類

@Component
public class UserClientFallBack implements UserClient {
    @Override
    public User queryUserById(Long id) {
        User user = new User();
        user.setUsername("服務器正忙,請稍后再試!!!");
        return user;
    }
}

然后在UserFeignClient中,指定剛才撰寫的實作類

@FeignClient(value = "service-provider", fallback = UserClientFallback.class) // 標注該類是一個feign介面
public interface UserClient {

    @GetMapping("user/{id}")
    User queryUserById(@PathVariable("id") Long id);
}

重啟測驗:
在這里插入圖片描述

請求壓縮:

Spring Cloud Feign 支持對請求和回應進行GZIP壓縮,以減少通信程序中的性能損耗,通過下面的引數即可開啟請求與回應的壓縮功能:

feign:
  compression:
    request:
      enabled: true # 開啟請求壓縮
    response:
      enabled: true # 開啟回應壓縮

同時,我們也可以對請求的資料型別,以及觸發壓縮的大小下限進行設定:

feign:
  compression:
    request:
      enabled: true # 開啟請求壓縮
      mime-types: text/html,application/xml,application/json # 設定壓縮的資料型別
      min-request-size: 2048 # 設定觸發壓縮的大小下限

注:上面的資料型別、壓縮大小下限均為默認值,

Zuul網關

通過前面的學習,使用Spring Cloud實作微服務的架構基本成型,大致是這樣的:

  • 使用Spring Cloud Netflix中的Eureka實作了服務注冊中心以及服務注冊與發現;
  • 服務間通過Ribbon或Feign實作服務的消費以及均衡負載,
  • 為了使得服務集群更為健壯,使用Hystrix的融斷機制來避免在微服務架構中個別服務出現例外時引起的故障蔓延,

在這里插入圖片描述

在該架構中,我們的服務集群包含:內部服務Service A和Service B,他們都會注冊與訂閱服務至Eureka Server,而Open Service是一個對外的服務,通過均衡負載公開至服務呼叫方,我們把焦點聚集在對外服務這塊,直接暴露我們的服務地址,這樣的實作是否合理,或者是否有更好的實作方式呢?

我們可以將權限控制這樣的東西從我們的服務單元中抽離出去,而最適合這些邏輯的地方就是處于對外訪問最前端的地方,我們需要一個更強大一些的均衡負載器的服務網關,

服務網關是微服務架構中一個不可或缺的部分,通過服務網關統一向外系統提供REST API的程序中,除了具備服務路由均衡負載功能之外,它還具備了權限控制等功能,Spring Cloud Netflix中的Zuul就擔任了這樣的一個角色,為微服務架構提供了前門保護的作用,同時將權限控制這些較重的非業務邏輯內容遷移到服務路由層面,使得服務集群主體能夠具備更高的可復用性和可測驗性,

Zuul網關官網:https://github.com/Netflix/zuul

在這里插入圖片描述

Zuul加入后的架構

在這里插入圖片描述

不管是來自于客戶端(PC或移動端)的請求,還是服務內部呼叫,一切對服務的請求都會經過Zuul這個網關,然后再由網關來實作 鑒權、動態路由等等操作,Zuul就是我們服務的統一入口,

快速入門

新建工程:

在這里插入圖片描述
在這里插入圖片描述

添加Zuul依賴:
在這里插入圖片描述
在這里插入圖片描述
工程目錄:
在這里插入圖片描述
pom.xml檔案

<?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.11.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ly</groupId>
    <artifactId>ly-zuul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ly-zuul</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</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>

新建application.yml檔案,撰寫配置

server:
  port: 10010   #服務埠
spring:
  application:
    name: ly-zuul  #指定服務名

撰寫引導類:

通過@EnableZuulProxy注解開啟Zuul的功能:

@SpringBootApplication
@EnableZuulProxy // 開啟網關功能
public class ItcastZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(ItcastZuulApplication.class, args);
    }
}

撰寫路由規則:

我們需要用Zuul來代理service-provider服務,先看一下控制面板中的服務狀態:

在這里插入圖片描述

映射規則:

server:
  port: 10010
spring:
  application:
    name: ly-zuul

zuul:
  routes:
    service-provider: /service-provider/** #路由名稱,可以隨便起,習慣上是服務名
      path: /service-provider/**   # 這里是映射路徑
      url: http://localhost:8081   # 映射路徑對應的實際url地址

我們將符合path 規則的一切請求,都代理到 url引數指定的地址

本例中,我們將 /service-provider/**開頭的請求,代理到http://localhost:8081

啟動測驗:

訪問的路徑中需要加上配置規則的映射路徑,我們訪問:http://localhost:10010/service-provider/user/2
在這里插入圖片描述

面向服務的路由

在剛才的路由規則中,我們把路徑對應的服務地址寫死了!如果同一服務有多個實體的話,這樣做顯然就不合理了,我們應該根據服務的名稱,去Eureka注冊中心查找 服務對應的所有實體串列,然后進行動態路由才對!

對ly-zuul工程修改優化,添加Eureka客戶端依賴:

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

添加Eureka配置,獲取服務資訊:

eureka:
  client:
    registry-fetch-interval-seconds: 5 # 獲取服務串列的周期:5s
    service-url:
      defaultZone: http://localhost:10086/eureka

開啟Eureka客戶端發現功能:

@SpringBootApplication
@EnableZuulProxy  //啟用zuul網關組件
@EnableDiscoveryClient  //啟用客戶端
public class LyZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(LyZuulApplication.class, args);
    }

}

修改映射配置,通過服務名稱獲取:

因為已經有了Eureka客戶端,我們可以從Eureka獲取服務的地址資訊,因此映射時無需指定IP地址,而是通過服務名稱來訪問,而且Zuul已經集成了Ribbon的負載均衡功能,

zuul:
  routes:
    service-provider: # 這里是路由id,隨意寫
      path: /service-provider/** # 這里是映射路徑
      serviceId: service-provider # 指定服務名稱

啟動測驗:

再次啟動,這次Zuul進行代理時,會利用Ribbon進行負載均衡訪問:

在這里插入圖片描述

路由配置的四種方式: (一般使用的是第三種)

zuul:
  routes:
    service-provider: 
      path: /service-provider/** #路由名稱,可以隨便起,習慣上是服務名
      url: http://localhost:8081
    
zuul:
  routes:
    service-provider:
      path: /service-provider/**   #路由名稱,可以隨便起,習慣上是服務名
      serviceId: service-provider  #指定服務名
      
#而大多數情況下,路由名稱往往和服務名會寫成一樣的,因此Zuul就提供了一種簡化的配置語法:
zuul:
  routes:
    service-provider: /provider/** #路由名稱,可以隨便起,習慣上是服務名
 
-不用配置,默認就是服務id開頭路徑 
-Zuul就指定了默認的路由規則:默認情況下,一切服務的映射路徑就是服務名本身

測驗第三種方法:使用prefix: /*配置虛擬路徑

zuul:
  routes:
    service-provider: /provider/** #路由名稱,可以隨便起,習慣上是服務名
  prefix: /api  #虛擬路徑

在這里插入圖片描述

過濾器

Zuul作為網關的其中一個重要功能,就是實作請求的鑒權,而這個動作我們往往是通過Zuul提供的過濾器來實作的,

ZuulFilter:
ZuulFilter是過濾器的頂級父類,在這里我們看一下其中定義的4個最重要的方法:

public abstract ZuulFilter implements IZuulFilter{

    abstract public String filterType();

    abstract public int filterOrder();
    
    boolean shouldFilter();// 來自IZuulFilter

    Object run() throws ZuulException;// IZuulFilter
}
  • shouldFilter:回傳一個Boolean值,判斷該過濾器是否需要執行,回傳true執行,回傳false不執行,
  • run:過濾器的具體業務邏輯,
  • filterType:回傳字串,代表過濾器的型別,包含以下4種:
    • pre:請求在被路由之前執行
    • route:在路由請求時呼叫
    • post:在route和errror過濾器之后呼叫
    • error:處理請求時發生錯誤呼叫
  • filterOrder:通過回傳的int值來定義過濾器的執行順序,數字越小優先級越高,

過濾器執行生命周期:

這張是Zuul官網提供的請求生命周期圖,清晰的表現了一個請求在各個過濾器的執行順序,

在這里插入圖片描述

正常流程:

  • 請求到達首先會經過pre型別過濾器,而后到達route型別,進行路由,請求就到達真正的服務提供者,執行請求,回傳結果后,會到達post過濾器,而后回傳回應,

例外流程:

  • 整個程序中,pre或者route過濾器出現例外,都會直接進入error過濾器,在error處理完畢后,會將請求交給POST過濾器,最后回傳給用戶,
  • 如果是error過濾器自己出現例外,最終也會進入POST過濾器,將最終結果回傳給請求客戶端,
  • 如果是POST過濾器出現例外,會跳轉到error過濾器,但是與pre和route不同的是,請求不會再到達POST過濾器了,

所有內置過濾器串列:

在這里插入圖片描述

使用場景:

  • 請求鑒權:一般放在pre型別,如果發現沒有訪問權限,直接就攔截了
  • 例外處理:一般會在error型別和post型別過濾器中結合來處理,
  • 服務呼叫時長統計:pre和post結合使用,

自定義過濾器:

接下來我們來自定義一個過濾器,模擬一個登錄的校驗,基本邏輯:如果請求中有access-token引數,則認為請求有效,放行,

定義過濾器類:

@Component
public class LoginFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 執行順序,回傳值越小,優先級越高
     * @return
     */
    @Override
    public int filterOrder() {
        return 10;
    }

    /**
     * 是否執行該過濾器
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 撰寫過濾器的業務邏輯
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        //初始化context背景關系物件,servlet spring
        RequestContext context =RequestContext.getCurrentContext();

        //獲取request物件
        HttpServletRequest request =context.getRequest();

        //獲取引數
        String token =request.getParameter("token");
        if(StringUtils.isBlank(token)){
            //攔截,不轉發請求
            context.setSendZuulResponse(false);
            //回應狀態碼,401-身份未認證
            context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
            //設定回應的提示
            context.setResponseBody("request error!");
        }

        //回傳值為null,就代表該過濾器什么都不做
        return null;
    }
}

運行測驗:

沒有token引數時,訪問失敗:
在這里插入圖片描述

添加token引數后:

在這里插入圖片描述

負載均衡和熔斷:

Zuul中默認就已經集成了Ribbon負載均衡和Hystix熔斷機制,但是所有的超時策略都是走的默認值,比如熔斷超時時間只有1S,很容易就觸發了,因此建議我們手動進行配置:

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000 # 設定hystrix的超時時間為6000ms

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/233997.html

標籤:其他

上一篇:jetson的ubuntu18.04上安裝中文輸入法

下一篇:戲(細)說作業流——activiti

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more