当前位置: 首页 > news >正文

7.1 微服务-SpringCloud(二)

目录

前言

7.1.5 Hystrix

7.1.5.1 什么是Hystrix

7.1.5.2 雪崩问题

7.1.5.3 线程隔离,服务降级

7.1.5.4 搭建

7.1.5.4.1 引入依赖

7.1.5.4.2 开启熔断

7.1.5.4.3 编写降级逻辑

1.局部降级逻辑

2.全局降级逻辑

7.1.5.4.4 设置超时

7.1.5.5 服务熔断

7.1.6 Feign

7.1.6.1 什么是Feign

7.1.6.2 快速入门

7.1.6.2.1 引入依赖

7.1.6.2.2 开启Feign功能

7.1.6.2.3 Feign的客户端

7.1.6.2.4 测试

7.1.6.3 负载均衡

7.1.6.4 Hystrix

7.1.6.5 请求压缩

7.1.6.6 日志级别

7.1.7 Zuul网关

7.1.7.1 Zuul概述

7.1.7.1.1 问题

7.1.7.1.2 Zuul

7.1.7.1.3 Zuul加入后的架构

7.1.7.2 快速入门

7.1.7.2.1 添加依赖

7.1.7.2.2 配置

7.1.7.2.3 启动类添加注解

7.1.7.2.4 编写路由规则

7.1.7.3 面向服务的路由

7.1.7.3.1 添加Eureka客户端依赖

7.1.7.3.2 添加Eureka配置,获取服务信息

7.1.7.3.3 启动类开启Eureka客户端发现功能

7.1.7.3.4 修改映射配置,通过服务名称获取

7.1.7.4 简化的路由配置

7.1.7.5 默认的路由规则

7.1.7.6 路由前缀

7.1.7.7 过滤器

7.1.7.7.1 ZuulFilter

7.1.7.7.2 过滤器执行生命周期

7.1.7.8 自定义过滤器

7.1.7.9 负载均衡和熔断


前言

SpringCloud组件使用套路,三步走

  1. 引入组件的启动器
  2. 覆盖默认配置
  3. 在引导类上添加注解,开发相关组件 

重点理解SpringCloud这些组件的使用细节,知道每个阶段出现的注解,它们的顺序以及具体功能

7.1.5 Hystrix

7.1.5.1 什么是Hystrix

Hystrix,[hɪst'rɪks],英文意思是豪猪,是一种保护机制。

Hystrix也是Netflix公司的一款组件。

主页:GitHub - Netflix/Hystrix: Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.

Hystix作用:

Hystix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败。  

7.1.5.2 雪崩问题

微服务中,服务间调用关系错综复杂,一个请求,可能需要调用多个微服务接口才能实现,会形成非常复杂的调用链路:  

 如图,一次业务请求,需要调用A、P、H、I四个服务,这四个服务又可能调用其它服务。

如果此时,某个服务出现异常:

例如微服务I发生异常,请求阻塞,用户不会得到响应,则tomcat的这个线程不会释放,于是越来越多的用户请求到来,越来越多的线程会阻塞:

 服务器支持的线程和并发数有限,请求一直阻塞,会导致服务器资源耗尽,从而导致所有其它服务都不可用,形成雪崩效应。

这就好比,一个汽车生产线,生产不同的汽车,需要使用不同的零件,如果某个零件因为种种原因无法使用,那么就会造成整台车无法装配,陷入等待零件的状态,直到零件到位,才能继续组装。  此时如果有很多个车型都需要这个零件,那么整个工厂都将陷入等待的状态,导致所有生产都陷入瘫痪。一个零件的波及范围不断扩大。

Hystix解决雪崩问题的手段有两个:

  • 线程隔离

  • 服务熔断

7.1.5.3 线程隔离,服务降级

Hystrix为每个依赖服务调用分配一个小的线程池,如果线程池已满调用将被立即拒绝,默认不采用排队.加速失败判定时间。

用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,或者请求超时,则会进行降级处理,什么是服务降级?

服务降级:优先保证核心服务,而非核心服务不可用或弱可用。

用户的请求故障时,不会被阻塞,更不会无休止的等待或者看到系统崩溃,至少可以看到一个执行结果(例如返回友好的提示信息) 。

服务降级虽然会导致请求失败,但是不会导致阻塞,而且最多会影响这个依赖服务对应的线程池中的资源,对其它服务没有响应。

触发Hystix服务降级的情况:

  • 线程池已满

  • 请求超时

7.1.5.4 搭建

7.1.5.4.1 引入依赖

在消费者的pom.xml中引入Hystrix依赖:

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

7.1.5.4.2 开启熔断

在消费者启动器中加入注解

@EnableCircuitBreaker

或者使用组合注解

@SpringCloudApplication  

/*
@SpringBootApplication
@EnableDiscoveryClient //springcloud提供的
@EnableCircuitBreaker//启用断路器(熔断器)
*/
@SpringCloudApplication  //组合注解,相当于上面三个注解
public class ConsumerApplication {

7.1.5.4.3 编写降级逻辑

1.局部降级逻辑

降级方法要和被降级的方法参数列表一致,返回值也要一致

在需要降级的方法中使用注解@HystrixCommand(fallbackMethod = "findByIdFallback") ,指定降级方法的方法名

@Controller
@RequestMapping("/consumer")
public class UserController {@ResourceRestTemplate restTemplate;@AutowiredDiscoveryClient discoveryClient;@RequestMapping("/findbyid/{id}")@ResponseBody@HystrixCommand(fallbackMethod = "findByIdFallback") //指定降级方法的方法名public String findById(@PathVariable Integer id){// 调用User user = restTemplate.getForObject("http://service-provider/provider/findbyid/" + id, User.class);return user.toString();}//降级方法要和被降级的方法参数列表一致,返回值也要一致public String findByIdFallback(Integer id){//处理return "服务器正忙,请稍后重试";}
}

2.全局降级逻辑

全局降级逻辑(默认FallBack、默认降级逻辑)

局部降级逻辑把fallback写在了某个业务方法上,如果这样的方法很多,会很冗余。因此把Fallback配置加在类上),实现默认fallback:

@DefaultProperties(defaultFallback = "defaultFallBack"):在类上指明统一的失败降级方法

@HystrixCommand:在方法上直接使用该注解,使用默认的降级方法。

定义defaultFallback:默认降级方法,不用任何参数,以匹配更多方法,但是返回值一定一致

@Controller
@RequestMapping("/consumer")
@DefaultProperties(defaultFallback = "defaultFasllback")//指定全局降级方法的方法名
public class UserController {@ResourceRestTemplate restTemplate;@AutowiredDiscoveryClient discoveryClient;@AutowiredUserFeign userFeign;@RequestMapping("/findbyid/{id}")@ResponseBody@HystrixCommand //方法上的注解不能省略,因为不是所有的方法都需要降级方法public String findById(@PathVariable Integer id){User user = userFeign.findById(id);return user.toString();}//全局降级方法//降级方法要和被降级的方法参数列表一致,那跟谁保持一致呢?那就不要参数了,返回值也一致,那就用stringpublic String defaultFasllback(){return "网络拥挤,请稍后再试~~~";}
}

7.1.5.4.4 设置超时

在之前的案例中,请求在超过1秒后都会返回错误信息,这是因为Hystix的默认超时时长为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(6000);} catch (InterruptedException e) {e.printStackTrace();}return this.userService.queryUserById(id);
}

7.1.5.5 服务熔断

熔断器,也叫断路器,其英文单词为:Circuit Breaker

熔断机制,在分布式系统中,服务调用方可以自己进行判断某些服务反应慢或者存在大量超时的情况时,能够主动熔断,防止整个系统被拖垮。

Hystrix可以实现弹性容错,当情况好转后,可以自动连接。

通过断路的方式,可以将后续请求直接拒绝,一段时间后允许部分请求通过,如果调用成功则回到闭合状态,否则继续断开

熔断状态机3个状态:

  • Closed:关闭状态,所有请求都正常访问。
  • Open:打开状态,所有请求都会被降级。Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值是50%,请求次数最少不低于20次。
  • Half Open:半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会完全关闭断路器,否则继续保持打开,再次进行休眠计时

不过,默认的熔断触发要求较高,休眠时间窗较短,为了测试方便,我们可以通过配置修改熔断策略:

circuitBreaker.requestVolumeThreshold=10
circuitBreaker.sleepWindowInMilliseconds=10000
circuitBreaker.errorThresholdPercentage=50
  • requestVolumeThreshold:触发熔断的最小请求次数,默认20

  • errorThresholdPercentage:触发熔断的失败请求最小占比,默认50%

  • sleepWindowInMilliseconds:休眠时长,默认是5000毫秒

7.1.6 Feign

7.1.6.1 什么是Feign

Fein ,[feɪn],假装,伪装

在前面的学习中,我们使用了Ribbon的负载均衡功能,大大简化了远程调用时的代码:

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

如果就学到这里,你可能以后需要编写类似的大量重复代码,格式基本相同,无非参数不一样。有没有更优雅的方式,来对这些代码再次优化呢?

这就是我们接下来要学的Feign的功能了。

什么是伪装?

Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。你不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做。

Feign是 Netflix开发的声明式、模板化的HTTP客户端,其灵感来自 Retrofit,JAXRS-2.0以及WebSocket。Feign 可帮助我们更加便捷、优雅地调用 HTTP API。

在Spring Cloud中,使用Feign 非常简单一一创建一个接口,并在接口上添加一些注解代码就完成了。Feign支持多种注解,例如 Feign自带的注解或者JAX-RS注解等。

Spring Cloud对 Feign进行了增强,使 Feign 支持了Spring MVC注解,并整合了 Ribbon和 Eureka,从而让 Feign的使用更加方便。

7.1.6.2 快速入门

7.1.6.2.1 引入依赖

在消费者模块中导入依赖

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

7.1.6.2.2 开启Feign功能

我们在启动类上,添加@EnableFeignClients注解,开启Feign功能

/*
@SpringBootApplication
@EnableDiscoveryClient //springcloud提供的
@EnableCircuitBreaker//启用断路器(熔断器)
*/@SpringCloudApplication  //组合注解,相当于上面三个注解
@EnableFeignClients // 开启feign客户端
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class,args);}
/*
删除@Bean@LoadBalancedRestTemplate restTemplate(){return new RestTemplate();}
*/}

删除RestTemplate:feign已经自动集成了Ribbon负载均衡的RestTemplate。所以,此处不需要再注册RestTemplate。  

7.1.6.2.3 Feign的客户端

创建UserFeign 接口

@FeignClient(value = "service-provider",fallback = UserFeignImpl.class)   //feign客户端,用于调用远程服务
public interface UserFeign {//可以使用springmvc注解//注意完整路径@RequestMapping("/provider/findbyid/{id}")User findById(@PathVariable("id") int id);
}

创建UserFeign 实现类UserFeignImpl 

@Component //放入容器
public class UserFeignImpl implements UserFeign {@Overridepublic User findById(int id) {User user = new User();user.setName("服务器繁忙,请稍后再试");return user;}
}
  • 这是一个接口,Feign会通过动态代理,帮我们生成实现类。这点跟mybatis的mapper很像
  • @FeignClient,声明这是一个Feign客户端,类似@Mapper注解。同时通过value属性指定服务名称
  • 接口中的定义方法,完全采用SpringMVC的注解,Feign会根据注解帮我们生成URL,并访问获取结果

修改controller中的调用逻辑

通过userFeign来获取

@Controller
@RequestMapping("/consumer")
@DefaultProperties(defaultFallback = "defaultFasllback")//指定全局降级方法的方法名
public class UserController {@ResourceRestTemplate restTemplate;@AutowiredDiscoveryClient discoveryClient;@AutowiredUserFeign userFeign;@RequestMapping("/findbyid/{id}")@ResponseBody@HystrixCommand //方法上的注解不能省略,因为不是所有的方法都需要降级方法public String findById(@PathVariable Integer id){// 调用User user = userFeign.findById(id);return user.toString();}
}

7.1.6.2.4 测试

启动模块

 输入  localhost:消费者端口号/以及路径/二级路径/id

7.1.6.3 负载均衡

Feign中本身已经集成了Ribbon依赖和自动配置:

因此我们不需要额外引入依赖,也不需要再注册RestTemplate对象。

7.1.6.4 Hystrix

Feign默认也有对Hystrix的集成

 只不过,默认情况下是关闭的。我们需要通过下面的参数来开启:(在消费者模块添加配置内容)

feign:hystrix:enabled: true # 开启Feign的熔断功能

但是,Feign中的Fallback配置不像hystrix中那样简单了。

1)首先,我们要定义一个类UserClientFallback,实现刚才编写的UserClient,作为fallback的处理类

@Component
public class UserClientFallback implements UserClient {
​@Overridepublic User queryById(Long id) {User user = new User();user.setUserName("服务器繁忙,请稍后再试!");return user;}
}

2)然后在UserFeignClient中,指定刚才编写的实现类

@FeignClient(value = "service-provider", fallback = UserClientFallback.class) // 标注该类是一个feign接口
public interface UserClient {
​@GetMapping("user/{id}")User queryUserById(@PathVariable("id") Long id);
}

3)重启测试:

7.1.6.5 请求压缩

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 # 设置触发压缩的大小下限

注:上面的数据类型、压缩大小下限均为默认值。

7.1.6.6 日志级别

前面讲过,通过logging.level.xx=debug来设置日志级别。然而这个对Fegin客户端而言不会产生效果。因为@FeignClient注解修饰的客户端在被代理时,都会创建一个新的Fegin.Logger实例。我们需要额外指定这个日志的级别才可以。

1)设置cn.bl包下的日志级别都为debug

logging:level:cn.bl: debug

2)编写配置类,定义日志级别

@Configuration
public class FeignLogConfiguration {
​@BeanLogger.Level feignLoggerLevel(){return Logger.Level.FULL;}
}

这里指定的Level级别是FULL,Feign支持4种级别:

  • NONE:不记录任何日志信息,这是默认值
  • BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
  • HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
  • FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据

3)在FeignClient中指定配置类:

@FeignClient(value = "service-privider", fallback = UserFeignClientFallback.class, configuration = FeignConfig.class)
public interface UserFeignClient {@GetMapping("/user/{id}")User queryUserById(@PathVariable("id") Long id);
}

4)重启项目,即可看到每次访问的日志:

7.1.7 Zuul网关

7.1.7.1 Zuul概述

7.1.7.1.1 问题

我们使用SpringCloud Netflix中的Eureka实现了服务注册中心以及服务注册与发现;而服务间通过Ribbon或Feign实现服务的消费以及均衡负载。为了使得服务集群更为健壮,使用Hystrix的融断机制来避免在微服务架构中个别服务出现异常时引起的故障蔓延。

在该架构中,我们的服务集群包含:内部服务Service A和Service B,他们都会注册与订阅服务至Eureka Server,而Open Service是一个对外的服务,通过均衡负载公开至服务调用方。我们把焦点聚集在对外服务这块,直接暴露我们的服务地址,这样的实现是否合理,或者是否有更好的实现方式呢?

先来说说这样架构需要做的一些事儿以及存在的不足:

  • 破坏了服务无状态特点。

    为了保证对外服务的安全性,我们需要实现对服务访问的权限控制,而开放服务的权限控制机制将会贯穿并污染整个开放服务的业务逻辑,这会带来的最直接问题是,破坏了服务集群中REST API无状态的特点。 从具体开发和测试的角度来说,在工作中除了要考虑实际的业务逻辑之外,还需要额外考虑对接口访问的控制处理。

  • 无法直接复用既有接口。

    当我们需要对一个即有的集群内访问接口,实现外部服务访问时,我们不得不通过在原有接口上增加校验逻辑,或增加一个代理调用来实现权限控制,无法直接复用原有的接口。

面对类似上面的问题,我们要如何解决呢?答案是:服务网关

为了解决上面这些问题,我们需要将权限控制这样的东西从我们的服务单元中抽离出去,而最适合这些逻辑的地方就是处于对外访问最前端的地方,我们需要一个更强大一些的均衡负载器的 服务网关。

服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由均衡负载功能之外,它还具备了权限控制等功能。SpringCloud Netflix中的Zuul就担任了这样的一个角色,为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。

zuul主要是请求的鉴权,部署在“门口”,如下图

7.1.7.1.2 Zuul

Zuul是Netflix开源的微服务网关,它可以和 Eureka、Ribbon、Hystrix等组件配合使用。Zuul 的核心是一系列的过滤器,这些过滤器可以完成以下功能:

  • 身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符的请求。
  • 审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
  • 动态路由:动态地将请求路由到不同的后端集群。
  • 压力测试:逐渐增加指向集群的流量,以了解性能。
  • 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求。
  • 静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群.
  • 多区域弹性:跨越AWS Region进行请求路由,旨在实现ELB (Elastic Load Balancing )使用的多样化,以及让系统的边缘更贴近系统的使用者。

SpringCloud对Zuul进行了整合与增强。目前,Zuul使用的默认HTTP客户端是 Apache HTTP Client,也可以使用RestClient或者okhttp3.OkHttpClient。如果想要使用RestClient,可以设置ribbon.restclient.enabled=true;

7.1.7.1.3 Zuul加入后的架构

不管是来自于客户端(PC或移动端)的请求,还是服务内部调用。一切对服务的请求都会经过Zuul这个网关,然后再由网关来实现 鉴权、动态路由等等操作。Zuul就是我们服务的统一入口。

7.1.7.2 快速入门

7.1.7.2.1 添加依赖

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

7.1.7.2.2 配置

server:port: 10010 #服务端口
spring:application:name: api-gateway #指定服务名

7.1.7.2.3 启动类添加注解

添加@EnableZuulProxy 

@SpringBootApplication
@EnableZuulProxy // 开启网关功能
public class YhZuulApplication {public static void main(String[] args) {SpringApplication.run(YhZuulApplication.class, args);}
}

7.1.7.2.4 编写路由规则

我们需要用Zuul来代理service-provider服务,先看一下控制面板中的服务状态:

  • ip为:127.0.0.1

  • 端口为:8081

映射规则:

server:port: 10010 #服务端口
spring:application:name: api-gateway #指定服务名
zuul:routes:service-provider: # 这里是路由id,随意写path: /service-provider/** # 这里是映射路径url: http://127.0.0.1:8081 # 映射路径对应的实际url地址

我们将符合path 规则的一切请求,都代理到 url参数指定的地址

本例中,我们将 /service-provider/**开头的请求,代理到http://127.0.0.1:8081

7.1.7.3 面向服务的路由

在刚才的路由规则中,我们把路径对应的服务地址写死了!如果同一服务有多个实例的话,这样做显然就不合理了。我们应该根据服务的名称,去Eureka注册中心查找 服务对应的所有实例列表,然后进行动态路由才对!

7.1.7.3.1 添加Eureka客户端依赖

在zuul模块中引入依赖

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

7.1.7.3.2 添加Eureka配置,获取服务信息

eureka:client:registry-fetch-interval-seconds: 5 # 获取服务列表的周期:5sservice-url:defaultZone: http://127.0.0.1:10086/eureka

7.1.7.3.3 启动类开启Eureka客户端发现功能

@SpringBootApplication
@EnableZuulProxy // 开启Zuul的网关功能
@EnableDiscoveryClient
public class ZuulDemoApplication {public static void main(String[] args) {SpringApplication.run(ZuulDemoApplication.class, args);}
}

7.1.7.3.4 修改映射配置,通过服务名称获取

因为已经有了Eureka客户端,我们可以从Eureka获取服务的地址信息,因此映射时无需指定IP地址,而是通过服务名称来访问,而且Zuul已经集成了Ribbon的负载均衡功能。

zuul:routes:service-provider: # 这里是路由id,随意写path: /service-provider/** # 这里是映射路径serviceId: service-provider # 指定服务名称

7.1.7.4 简化的路由配置

在刚才的配置中,我们的规则是这样的:

  • zuul.routes.<route>.path=/xxx/**: 来指定映射路径。<route>是自定义的路由名

  • zuul.routes.<route>.serviceId=service-provider:来指定服务名。

而大多数情况下,我们的<route>路由名称往往和服务名会写成一样的。因此Zuul就提供了一种简化的配置语法:zuul.routes.<serviceId>=<path>

比方说上面我们关于service-provider的配置可以简化为一条:

zuul:routes:service-provider: /service-provider/** # 这里是映射路径

省去了对服务名称的配置。

7.1.7.5 默认的路由规则

在使用Zuul的过程中,上面讲述的规则已经大大的简化了配置项。但是当服务较多时,配置也是比较繁琐的。因此Zuul就指定了默认的路由规则:

  • 默认情况下,一切服务的映射路径就是服务名本身。例如服务名为:service-provider,则默认的映射路径就是:/service-provider/**

也就是说,刚才的映射规则我们可以不配置

7.1.7.6 路由前缀

配置示例:

zuul:routes:service-provider: /service-provider/**service-consumer: /service-consumer/**prefix: /api # 添加路由前缀

我们通过zuul.prefix=/api来指定了路由的前缀,这样在发起请求时,路径就要以/api开头。

场景: 可以判断,哪些请求经过网关,哪些没有经过网关

7.1.7.7 过滤器

Zuul作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现的。

7.1.7.7.1 ZuulFilter

在IDEA中连续按两次SHIFT,搜索ZuulFilter

 

 ZuulFilter是过滤器的顶级父类。在这里我们看一下其中定义的4个最重要的方法:

public abstract ZuulFilter implements IZuulFilter{abstract public String filterType();abstract public int filterOrder();boolean shouldFilter();// 来自IZuulFilterObject run() throws ZuulException;// IZuulFilter
}
  • shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行。

  • run:过滤器的具体业务逻辑。

  • filterType:返回字符串,代表过滤器的类型。包含以下4种:

    • pre:请求在被路由之前执行

    • route:在路由请求时调用

    • post:在route和errror过滤器之后调用

    • error:处理请求时发生错误调用

  • filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。

进入IZuulFilter

里面定义了两个最基本的方法

 boolean shouldFilter();Object run() throws ZuulException;

所有的过滤器,包括自定义的过滤器都要实现这两个最基本的方法

 

7.1.7.7.2 过滤器执行生命周期

正常流程:

  • 请求到达首先会经过pre类型过滤器,而后到达route类型,进行路由,请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。

异常流程:

  • 整个过程中,pre或者route过滤器出现异常,都会直接进入error过滤器,在error处理完毕后,会将请求交给POST过滤器,最后返回给用户。

  • 如果是error过滤器自己出现异常,最终也会进入POST过滤器,将最终结果返回给请求客户端。

  • 如果是POST过滤器出现异常,会跳转到error过滤器,但是与pre和route不同的是,请求不会再到达POST过滤器了。

所有内置过滤器列表:

使用场景

  • 请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了

  • 异常处理:一般会在error类型和post类型过滤器中结合来处理。

  • 服务调用时长统计:pre和post结合使用。

7.1.7.8 自定义过滤器

描述:自定义一个过滤器,模拟一个登录的校验。基本逻辑:如果请求中有access-token参数,则认为请求有效,放行

创建gateway包,里面创建一个类LoginFilter 

@Component
public class LoginFilter extends ZuulFilter {/*** 过滤器类型,前置过滤器* @return*/@Overridepublic String filterType() {return "pre";}/*** 过滤器的执行顺序* @return*/@Overridepublic int filterOrder() {return 1;}/*** 该过滤器是否生效* @return*/@Overridepublic boolean shouldFilter() {return true;}/*** 登陆校验逻辑* @return* @throws ZuulException*/@Overridepublic Object run() throws ZuulException {//所有的请求对象都在RequestContext中//所有的响应对象都在ResponseContext中// 获取zuul提供的上下文对象RequestContext context = RequestContext.getCurrentContext();// 从上下文对象中获取请求对象HttpServletRequest request = context.getRequest();// 获取token信息String token = request.getParameter("access-token");// 判断if (StringUtils.isBlank(token)) {// 过滤该请求,不对其进行路由context.setSendZuulResponse(false);// 设置响应状态码,401context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);// 设置响应信息context.setResponseBody("{\"status\":\"401\", \"text\":\"request error!\"}");}// 校验通过,把登陆信息放入上下文信息,继续向后执行context.set("token", token);return null;}
}

测试 

7.1.7.9 负载均衡和熔断

Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制。但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了。因此建议我们手动进行配置:

hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 2000 # 设置hystrix的超时时间为6000ms

 

相关文章:

7.1 微服务-SpringCloud(二)

目录 前言 7.1.5 Hystrix 7.1.5.1 什么是Hystrix 7.1.5.2 雪崩问题 7.1.5.3 线程隔离&#xff0c;服务降级 7.1.5.4 搭建 7.1.5.4.1 引入依赖 7.1.5.4.2 开启熔断 7.1.5.4.3 编写降级逻辑 1.局部降级逻辑 2.全局降级逻辑 7.1.5.4.4 设置超时 7.1.5.5 服务熔断 7.…...

Spring的AOP开发-基于xml配置的AOP

Spring的AOP开发-基于xml配置的AOP xml方式AOP快速入门 通过配置文件的方式解决以下问题 配置哪些包、哪些类、哪些方法需要被增强配置目标方法要被哪些通知方法所增强&#xff0c;在目标方法执行之前还是之后执行增强 配置方式的设计、配置文件(注解)&#xff0c;Spring已…...

JAVA的垃圾收集器与内存分配策略【一篇文章直接看懂】

内存动态分配和垃圾收集技术是JAVA和C之间最大的区别之一 垃圾收集&#xff08;Garbage Collection&#xff0c;GC&#xff09;只办三件事&#xff1a; 哪些内存需要回收什么时候回收如何回收 对于对象回收的方法 引用计数法&#xff1a; 每处引用时1&#xff0c;引用失效…...

NLP学习——信息抽取

信息抽取 自动从半结构或无结构的文本中抽取出结构化信息的任务。常见的信息抽取任务有三类&#xff1a;实体抽取、关系抽取、事件抽取。 1、实体抽取 从一段文本中抽取出文本内容并识别为预定义的类别。 实体抽取任务中的复杂问题&#xff1a; 重复嵌套&#xff0c;原文中…...

【深度学习基础7】预训练、激活函数、权重初始化、块归一化

一、Unsupervised Pre-training 得益于 Hinton and Salakhutdinov 在 2006 年的开创性工作— 无监督预训(unsupervised pre-training);在《Reducing the dimensionality of data with neural networks.》这篇论文中,他们在 RBMs 中引入无监督预训练,下面我们将在Autoenco…...

MetaMQ

文章目录MetaMQMetaMQ 的优势在于&#xff1a;MetaMQ 的劣势也有&#xff1a;MetaMQ MetaMQ 是一个基于以太坊的可扩展分布式消息队列&#xff08;MQ&#xff09;系统&#xff0c;它可以支持大规模的分布式应用程序。MetaMQ 是一个开放源代码项目&#xff0c;它支持企业级应用程…...

热门盘点 | 10款评分最高的项目管理工具

项目管理软件可以让项目经理及时掌握项目进展可把复杂的任务分解简单帮助项目经理及时了解整个团队进展随着现代项目需求日趋复杂和个性选一个好的项目管理软件还是很有必要的① PingCode国内研发项目管理软件PingCode&#xff0c;它是国内软件研发项目榜单中评分最高的项目管理…...

若依框架---分页功能

继前几天我们学习若依管理系统中的代码生成工具&#xff0c;我们发现若依系统中还要很多值得学习的地方。今天我们来学习若依管理系统中的分页工具。 若依管理系统是前后端分离的&#xff08;准确的说&#xff0c;若依有前后端分离版本&#xff09;。 前端 若依前端的分页没…...

CHAPTER 3 Jenkins SVN GItlab

Jenkins SVN GItlab3.1 JenkinsSVN3.1.1 搭建SVN服务器1. 安装svn server2. 查看svn安装位置3. 创建版本库目录4. 创建svn版本库5. 配置修改6. 防火墙开启3690端口7. 启动SVN-server8. 客户端访问svn服务器3.1.2 测试脚本提交3.1.3 jenkins下载代码配置1. 安装Subversion插件2.…...

为什么Redis集群的最大槽数是16384个?

对于客户端请求的key&#xff0c;根据公式HASH_SLOTCRC16(key) mod 16384&#xff0c;计算出映射到哪个分片上&#xff0c;然后Redis会去相应的节点进行操作&#xff01; 为什么有16384个槽&#xff1f; Redis集群并没有使用一致性hash而是引入了哈希槽的概念。Redis 集群有16…...

餐饮企业数据可视化大屏(智慧餐饮)

随着信息技术的深入发展&#xff0c;数据大屏的适用场景日益广泛&#xff0c;集工作汇报、实时监控和预测分析等功能于一身。 数据可视化的本质是视觉对话&#xff0c;数据可视化将数据分析技术与图形技术结合&#xff0c;清晰有效地将分析结果信息进行解读和传达。 当前很多餐…...

Kafka安装及zookeeper is not a recognized option问题解决

一安装JAVA JDK&#xff08;略&#xff09; 二安装ZooKeeper 下载安装包&#xff0c;建议bin版本 http://zookeeper.apache.org/releases.html#download解压并进入ZooKeeper&#xff0c;将“zoo_sample.cfg”重命名为“zoo.cfg” D:\Kafka\apache-zookeeper-3.7.1-bin\conf…...

leetcode刷题 | 关于二叉树的题型总结1

leetcode刷题 | 关于二叉树的题型总结1 文章目录leetcode刷题 | 关于二叉树的题型总结1题目连接完全二叉树插入器在每个树行中找最大值找树左下角的值二叉树的右视图二叉树剪枝题目连接 919. 完全二叉树插入器 - 力扣&#xff08;LeetCode&#xff09; 515. 在每个树行中找最…...

webpack新手入门

前言&#xff1a; 如何配置webpack呢&#xff1f; webpack概念有哪些呢&#xff1f; 怎么快速理解并使用webpack呢&#xff1f; 文章目录一. 什么是webpack二. 安装webpack三. webpack的五个核心概念四. webpack配置五. loader加载器1. css处理2. 处理文件&#xff08;图片&…...

Redis中有常见数据类型

Redis的数据类型 string数据类型 string是redis最基本的类型&#xff0c;而且string类型是二进制安全的。意思是redis的string可以包含任何 数据&#xff0c;比如jpg图片或者序列化的对象 String类型是最基本的数据类型&#xff0c;一个redis中字符串value最多可以是512M r…...

【知识梳理】Go语言核心编程

基础知识 Go语言就是为了解决编程语言对并发支持不友好、编译速度慢、编程复杂这三个问题而诞生的 特点: Go语言选择组合思想,抛弃继承关系通过接口组合,自由组合成新接口,用接口实现层与层之间的解耦语言特性对比: package mainimport "fmt"func main() {fmt…...

Java中动态调用setter以及getter

0x00 前言 对于非专业程序员的安全人员来说&#xff0c;因为没有代码项目的积累&#xff0c;很多知识体系都不完善&#xff0c;所以有必要在一些常用的内容进行学习的总结。 在很多的调用链中都会用到**“动态调用setter以及getter”**这个知识点&#xff0c;比如经典的CB链&a…...

基于 NeRF 的 App 上架苹果商店!照片转 3D 只需一部手机,网友们玩疯了

前言 只用一部手机&#xff0c;现实中的 2D 照片就能渲染出 3D 模型&#xff1f; 没错&#xff0c;无需再手动上传电脑或安装激光雷达&#xff0c;苹果手机自带 App 就能生成 3D 模型。 这个名叫 Luma AI 的“NeRF APP”&#xff0c;正式上架 App Store 后爆火&#xff1a; 小…...

C++类与对象(中)

✅<1>主页&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;C &#x1f525;<3>创作者&#xff1a;我的代码爱吃辣 ☂️<4>开发环境&#xff1a;Visual Studio 2022 &#x1f4ac;<5>前言&#xff1a;C类中一共有六个默认成员函…...

计算机软件技术基础复习

数据结构 文章目录数据结构第一节 数据结构的基本概念第二节 线性结构线性表顺序表和链表的特点实现循环队列第三节 非线性结构树操作系统操作系统概述进程和程序存储空间的组织数据库技术数据库设计软件技术软件生命周期第一节 数据结构的基本概念 数据结构&#xff1a;指相互…...

python爬虫--beautifulsoup模块简介

BeautifulSoup 的引入 我们学习了正则表达式的相关用法&#xff0c;但是一旦正则写的有问题&#xff0c;可能得到的就不是我们想要的结果了&#xff0c;而且对于一个网页来说&#xff0c;都有一定的特殊的结构和层级关系&#xff0c;而且很多标签都有 id 或 class 来对作区分&…...

Swfit Copy On Write 原理解析

1. Swift Copy On write 原理是什么 Swift 中的 Copy On Write (COW) 技术是一种内存优化技术&#xff0c;其原理是在需要修改数据时才进行拷贝&#xff0c;以避免不必要的内存消耗。 COW 的实现主要依赖于 Swift 中的结构体和类的特性。对于结构体而言&#xff0c;它是值类型…...

【面试题】经典面试题:让 a == 1 a == 2 a == 3 成立?

一、问题解析 if (a == 1 && a == 2 && a == 3) {console.log(Win) } 复制代码 如何打印除Win? 看到题目的第一眼,我是蒙蔽的.怎么可能会有如此矛盾的情况发生呢?就相当于一个人怎么可能即是小孩,又是成年人,还是老年人呢? 冷静下来,发现一些端倪。...

我是歌手-C语言

“我是歌手”是成名歌手之间的比赛节目&#xff0c;2轮比赛中观众支持率最低者出局。 这里我们假设有n个歌手进行了m轮比赛&#xff0c;请求出局者&#xff08;m轮总分最低者&#xff09;。 输入n个歌手&#xff08;编号依次为1&#xff0c;2&#xff0c;......n&#xff09;…...

Acwing---112.雷达设备

雷达设备1.题目2.基本思想3.代码实现1.题目 假设海岸是一条无限长的直线&#xff0c;陆地位于海岸的一侧&#xff0c;海洋位于另外一侧。 每个小岛都位于海洋一侧的某个点上。 雷达装置均位于海岸线上&#xff0c;且雷达的监测范围为 d&#xff0c;当小岛与某雷达的距离不超…...

SSJ-21A AC220V静态【时间继电器】

系列型号&#xff1a; SSJ-11B静态时间继电器&#xff1b;SSJ-21B静态时间继电器 SSJ-21A静态时间继电器&#xff1b;SSJ-22A静态时间继电器 SSJ-22B静态时间继电器SSJ-42B静态时间继电器 SSJ-42A静态时间继电器SSJ-41A静态时间继电器 SSJ-41B静态时间继电器SSJ-32B静态时间继电…...

m序列发生器——Verilog设计

引言 本篇文章利用Verilog编写一个m序列发生器模块。本文会给出具体的设计、测试源码。 设计说明 模块功能说明: 支持任意位宽的随机数生成;支持本原多项式配置;支持初始种子配置;设计环境: 设计语言:Verilog HDL 设计验证平台:MATLAB R20222a、Vivado 2018.3 m 序列…...

Mysql—触发器

触发器 简介 触发器用于直接在某种操作后&#xff08;数据的增删改查等&#xff09;&#xff0c;通过事件执行设置触发器时的 sql 语句&#xff0c;具有原子性。 可通过 sql 语句直接编写&#xff0c;关键词&#xff1a;CREATE TRIGGER 触发器名称。 例如&#xff1a;在表 st…...

DVWA靶场通关和源码分析

文章目录一、Brute Force1.low2、medium3、High4、Impossible二、Command Injection1、Low2、Medium3、High三、CSRF1、Low2、Medium3、High4、Impossible四、File Inclusion1、Low2、Medium3、High五、File Upload1、Low2、Medium3、High4、Impossible六、 SQL注入1、Low2、Me…...

RocketMQ5.0.0消息存储<二>_消息存储流程

目录 一、消息存储概览 二、Broker接收消息 三、消息存储流程 1. DefaultMessageStore类 2. 存储流程 1)&#xff1a;同步与异步存储 2)&#xff1a;CommitLog异步存储消息 3)&#xff1a;提交消息&#xff08;Commit&#xff09; 四、参考资料 一、消息存储概览 如下图所…...

幼儿园网站建设工作总结/搜索app下载安装

介绍一款新的绘图神器&#xff1a;sviewgui。sviewgui介绍sviewgui是一个基于 PyQt 的 GUI&#xff0c;用于 csv 文件或 Pandas 的 DataFrame 的数据可视化。此 GUI 基于 matplotlib&#xff0c;您可以通过多种方式可视化您的 csv 文件。主要特点&#xff1a;Ⅰ 散点图、线图、…...

网站去掉index.html/腾讯企点注册

首先&#xff0c; equality 等同&#xff0c; identity 恒等。 &#xff0c; 两边值类型不同的时候&#xff0c;要先进行类型转换&#xff0c;再比较。 &#xff0c;不做类型转换&#xff0c;类型不同的一定不等。 下面分别说明&#xff1a; 先说 &#xff0c;这个比较简单。下…...

安康网站建设电话/微信指数官网

我不能告诉你如何确定应该阅读lang_perl或lang_ruby 。 但是看一下autocommand文档会给gzip文件带来一个例子( :he gzip-example )&#xff1a;augroup gzipautocmd!autocmd BufReadPre,FileReadPre *.gz set binautocmd BufReadPost,FileReadPost *.gz [,]!gunzipautocmd BufR…...

中文一级a做爰片免费网站/近期国家新闻

在阅读本教程之前&#xff0c;请提前下载好斗鱼伴侣或者OBS直播软件&#xff0c;如还未下载&#xff0c;可进入https://www.douyu.com/client?platform1下载斗鱼直播管家&#xff0c;内置斗鱼伴侣和OBS两款直播软件。下面附上这两款软件的基础开播教程(链接中附带有视频教程讲…...

公司网站开发/怎么制作个人网站

1.避免在索引列上使用NOT和&#xff01;&#xff0c;索引只能告诉我们什么存在与表中&#xff0c;不能告诉我们什么不存在表中 2.索引列上用>替代> 3.oracle采用自下而上的顺序解析where子句&#xff0c;因此表之间的连接必须放在其他where条件之前&#xff0c;那些可以过…...

永久免费素材网站/新app推广去哪里找

刚刚接触SpringBoot&#xff0c;说说踩过的坑&#xff0c;主要的还是要记录下来&#xff0c;供以后反省反省&#xff01; 今天主要讲讲 thymeleafsecurity 的搭建&#xff0c;SpringBoot的项目搭建应该比较简单&#xff0c;这里就不多说了。可以去网上找到很多。 一&#xff1a…...