spring cloudspringcloud学习Spring boot

zuul学习四:zuul 过滤器详解

2017-08-13  本文已影响7211人  二月_春风

学习是一个深入的过程,不停的反复的研究,不能浮于表面,要深入原理。

之前我们了解到springcloud zuul包含了对请求的路由和过滤两个功能,其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础;而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。然而实际上,路由功能在真正运行时,它的路由映射和请求转发都是由几个不同的过滤器完成的。其中,路由映射主要通过pre类型的过滤器完成,它将请求路径与配置的路由规则进行匹配,以找到需要转发的目标地址;而请求转发的部分则是由route类型的过滤器来完成,对pre类型过滤器获得的路由地址进行转发。所以说,过滤器可以说是zuul实现api网关功能最核心的部件,每一个进入zuul的http请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。

我们先看看zuul过滤器基础的抽象接口com.netflix.zuul.ZuulFilter

Base abstract class for ZuulFilters. The base class defines abstract methods to define:
filterType() - to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,"route" for routing to an origin, "post" for post-routing filters, "error" for error handling.We also support a "static" type for static responses see StaticResponseFilter.
ZuulFilters的基础抽象类。 基类定义抽象方法来定义:
filterType() - 按类型对过滤器进行分类。 Zuul中的标准类型是用于预路由过滤的“pre”,用于路由到原点的“route”,用于后路由过滤的“post”,用于错误处理的“error”。我们还支持静态响应的“static”类型过滤器 请参阅StaticResponseFilter

Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)
filterOrder() must also be defined for a filter. Filters may have the same filterOrder if precedence is not important for a filter. filterOrders do not need to be sequential.
任何过滤器类型的过滤器通过调用FilterProcessor.runFilters(type)创建,添加和运行的。
也必须为过滤器定义filterOrder()方法,就是过滤器执行的顺序。 filterOrders不需要是顺序的(只要保持一个大概的顺序就行了)。

ZuulFilters may be disabled using Archius Properties.
可以使用Archius Properties来设置禁用ZuulFilters。

By default ZuulFilters are static; they don't carry state. This may be overridden by overriding the isStaticFilter() property to false.
默认情况下ZuulFilters是静态的; 他们不携带状态。 这可以通过将isStaticFilter()属性重写为false来覆盖.

spring cloud zuul中实现的过滤器必须包含4个基本特征:过滤类型,执行顺序,执行条件,具体操作。这些步骤都是com.netflix.zuul.ZuulFilter接口中定义的4个抽象方法:

String filterType();

filterType:该函数需要返回一个字符串代表过滤器的类型,而这个类型就是在http请求过程中定义的各个阶段。在zuul中默认定义了4个不同的生命周期过程类型,具体如下

int filterOrder();

通过int值来定义过滤器的执行顺序,数值越小优先级越高。

boolean shouldFilter();

返回一个boolean值来判断该过滤器是否要执行。我们可以通过此方法来指定过滤器的有效范围。

Object run();

过滤器的具体逻辑。在该函数中,我们可以实现自定义的过滤逻辑,来确定是否要拦截当前的请求,不对其进行后续的路由,或是在请求路由返回结果之后,对处理结果做一些加工等。

请求生命周期

外部http请求到达api网关服务的时候,首先它会进入第一个阶段pre,在这里它会被pre类型的过滤器进行处理。该类型过滤器的主要目的是在进行请求路由之前做一些前置加工,比如请求的校验等。在完成了pre类型的过滤器处理之后,请求进入第二个阶段routing,也就是之前说的路由请求转发阶段,请求将会被routing类型的处理器处理。这里的具体处理内容就是将外部请求转发到具体服务实例上去的过程,当服务实例请求结果都返回之后,routing阶段完成,请求进入第三个阶段post。此时请求将会被post类型的过滤器处理,这些过滤器在处理的时候不仅可以获取到请求信息,还能获取到服务实例的返回信息,所以在post类型的过滤器中,我们可以对处理结果进行一些加工或转换等内容。另外,还有一个特殊的阶段error,该阶段只有在上述三个阶段中发生异常的时候才会触发,但是它的最后流向还是post类型的过滤器,因为它需要通过post过滤器将最终结果返回给请求客户端(对于error过滤器的处理,在spring cloud zuul的过滤链中实际上有一些不同)

zuul生命周期

核心过滤器

spring cloud zuul中,为了让api网关组件可以被更方便的使用,它在http请求生命周期的各个阶段默认实现了一批核心过滤器,它们会在api网关服务启动的时候被自动加载和启动。我们可以在源码中查看和了解它们,它们定义与spring-cloud-netflix-core模块的org.springframework.cloud.netflix.zuul.filters包下。在默认启动的过滤器中包含三种不同生命周期的过滤器,这些过滤器都非常重要,可以帮组我们理解zuul对外部请求处理的过程,以及帮助我们在此基础上扩展过滤器去完成自身系统需要的功能。

pre过滤器

我们可以在com.netflix.zuul.FilterProcessor中查看相关的逻辑,如下:

   /**
     * runs all filters of the filterType sType/ Use this method within filters to run custom filters by type
     *
     * @param sType the filterType.
     * @return
     * @throws Throwable throws up an arbitrary exception
     */
    public Object runFilters(String sType) throws Throwable {
        //4个阶段的filter执行
        if (RequestContext.getCurrentContext().debugRouting()) {
            Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
        }
        boolean bResult = false;
        List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
        if (list != null) {
            for (int i = 0; i < list.size(); i++) {
                ZuulFilter zuulFilter = list.get(i);
                Object result = processZuulFilter(zuulFilter);
                if (result != null && result instanceof Boolean) {
                    bResult |= ((Boolean) result);
                }
            }
        }
        return bResult;
    }

route过滤器

RibbonRoutingFilter的run方法 RibbonCommandContext SimpleHostRoutingFilter的run方法 forward方法 forwardRequest

知道配置类似zuul.routes.user-service.url=http://localhost:8080/这样的底层都是通过httpclient直接发送请求的,也就知道为什么这样的情况没有做到负载均衡的原因所在。

SendForwardFilter的run方法

post过滤器

SendErrorFilter的run方法

本博客代码
代码地址

上一篇 下一篇

猜你喜欢

热点阅读