美文网首页
(二)zuul源码-Zuul组件中相关的路由过滤器

(二)zuul源码-Zuul组件中相关的路由过滤器

作者: guessguess | 来源:发表于2021-10-29 16:13 被阅读0次

    那么如何给对应的请求找到处理器?

    那么在讲查找过程的时候,需要去了解一下重要的接口。

    重要的接口

    ZuulFilterResult

    用于存储ZuulFilter的执行结果

    public final class ZuulFilterResult {
        private Object result;
        private Throwable exception;
        private ExecutionStatus status;
    }
    

    ZuulFilter

    ZuulFilter过滤器接口
    public interface IZuulFilter {
        //判断是否要拦截
        boolean shouldFilter();
        //运行
        Object run() throws ZuulException;
    }
    模板模式-核心实现。具体指定了ZuulFIlter的执行过程。
    public abstract class ZuulFilter implements IZuulFilter, Comparable<ZuulFilter> {
        过滤器的类型-分为pre post route error,由过滤器的子类去实现。
        abstract public String filterType();
        public ZuulFilterResult runFilter() {
            ZuulFilterResult zr = new ZuulFilterResult();
            需要开启过滤
            if (!isFilterDisabled()) {
                if (shouldFilter()) {
                    Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());
                    try {
                        Object res = run();
                        zr = new ZuulFilterResult(res, ExecutionStatus.SUCCESS);
                    } catch (Throwable e) {
                        t.setName("ZUUL::" + this.getClass().getSimpleName() + " failed");
                        zr = new ZuulFilterResult(ExecutionStatus.FAILED);
                        zr.setException(e);
                    } finally {
                        t.stopAndLog();
                    }
                } else {
                    zr = new ZuulFilterResult(ExecutionStatus.SKIPPED);
                }
            }
            return zr;
        }
    }
    

    FilterRegistry

    这个类很简单,就是用于过滤器注册的。

    public class FilterRegistry {
        private static final FilterRegistry INSTANCE = new FilterRegistry();
        public static final FilterRegistry instance() {
            return INSTANCE;
        }
        private final ConcurrentHashMap<String, ZuulFilter> filters = new ConcurrentHashMap<String, ZuulFilter>();
        private FilterRegistry() {
        }
        public ZuulFilter remove(String key) {
            return this.filters.remove(key);
        }
        public ZuulFilter get(String key) {
            return this.filters.get(key);
        }
        public void put(String key, ZuulFilter filter) {
            this.filters.putIfAbsent(key, filter);
        }
        public int size() {
            return this.filters.size();
        }
        public Collection<ZuulFilter> getAllFilters() {
            return this.filters.values();
        }
    }
    

    FilterLoader

    这个类其实就是用来存储过滤器以及对过滤器分类,以及加载过滤器的。

    public class FilterLoader {
        final static FilterLoader INSTANCE = new FilterLoader();
        private final ConcurrentHashMap<String, Long> filterClassLastModified = new ConcurrentHashMap<String, Long>();
        private final ConcurrentHashMap<String, String> filterClassCode = new ConcurrentHashMap<String, String>();
        private final ConcurrentHashMap<String, String> filterCheck = new ConcurrentHashMap<String, String>();
        private final ConcurrentHashMap<String, List<ZuulFilter>> hashFiltersByType = new ConcurrentHashMap<String, List<ZuulFilter>>();
        private FilterRegistry filterRegistry = FilterRegistry.instance();
    }
    

    FilterProcessor

    <span id="FilterProcessor">FilterProcessor的runFilters方法</span>
    这个类就是过滤器处理器,其实zuul处理请求都是通过过滤器的形式去处理的。
    最重要的地方在于定义了如何利用过滤器去执行请求。

    public class FilterProcessor {
        static FilterProcessor INSTANCE = new FilterProcessor();
        public Object runFilters(String sType) throws Throwable {
            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;
        }
    }
    

    1.Zuul组件如何实现动态过滤?

    Zuul组件如何实现动态过滤

    2.Zuul相关过滤器的注册以及作用

    其实在前面已经知道,Zuul是以过滤器的方式来运行的。从FilterProcessor的runFilters方法得知代码点击此处
    那么Zuul有什么类型的过滤器?

    Pre-路由前需要执行的过滤器(其实就是路由前需要做的操作)

    org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter
    org.springframework.cloud.netflix.zuul.filters.pre.ServletDetectionFilter
    org.springframework.cloud.netflix.zuul.filters.pre.FormBodyWrapperFilter
    org.springframework.cloud.netflix.zuul.filters.pre.DebugFilter
    org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter

    Route-路由时执行的过滤器(其实就是路由时需要做的操作)

    org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter
    org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter
    org.springframework.cloud.netflix.zuul.filters.route.SendForwardFilter

    Post-路由后执行的过滤器(其实就是路由后需要做的操作)

    org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter

    Error-发送错误时执行的过滤器

    org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter

    以上的过滤器的注册时机

    源码如下

    public class ZuulFilterInitializer {
        @PostConstruct
        public void contextInitialized() {
            log.info("Starting filter initializer");
    
            TracerFactory.initialize(tracerFactory);
            CounterFactory.initialize(counterFactory);
    
            for (Map.Entry<String, ZuulFilter> entry : this.filters.entrySet()) {
                filterRegistry.put(entry.getKey(), entry.getValue());
            }
        }
    }
    

    由于最后根据类型获取的时候会进行分类以及排序(order值越小,执行的优先级越高)。最后对应的过滤器链如下

    pre-org.springframework.cloud.netflix.zuul.filters.pre.ServletDetectionFilter  
          org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter
          org.springframework.cloud.netflix.zuul.filters.pre.FormBodyWrapperFilter
          org.springframework.cloud.netflix.zuul.filters.pre.DebugFilte
          org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter
    route- org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter
              org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter
              org.springframework.cloud.netflix.zuul.filters.route.SendForwardFilter
    post- org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter
    error-org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter
    

    Route类型的过滤器的作用

    由于Pre 以及 Post其实作用都很明显了,就不去了解了。因为其实最主要的是关心如何去路由。
    以下是route类型的过滤器的执行顺序。

    RibbonRoutingFilter

    RibbonRoutingFilter的拦截方法

        @Override
        public boolean shouldFilter() {
            RequestContext ctx = RequestContext.getCurrentContext();
            return (ctx.getRouteHost() == null && ctx.get(SERVICE_ID_KEY) != null
                    && ctx.sendZuulResponse());
        }
    

    对应的路由规则
    application.yml中的配置

    zuul:
      routes:
        advice1: 随便取个名字 路由规则1  
          path: /client/xxx  请求路径
          serviceId: client  映射到的服务Id
    

    所以这里很清晰明了,只要RequestContext中包含service-id且没有route-host,就会被RibbonRoutingFilter拦截。

    SimpleHostRoutingFilter

    SimpleHostRoutingFilter的拦截方法

        @Override
        public boolean shouldFilter() {
            return RequestContext.getCurrentContext().getRouteHost() != null
                    && RequestContext.getCurrentContext().sendZuulResponse();
        }
    

    application.yml中的配置

    zuul:
      routes:
        advice2:
          path: /client/xxx
          url: https://www.jianshu.com/
    

    只要有route-host就会被SimpleHostRoutingFilter处理

    SendForwardFilter
        @Override
        public boolean shouldFilter() {
            RequestContext ctx = RequestContext.getCurrentContext();
            return ctx.containsKey(FORWARD_TO_KEY)
                    && !ctx.getBoolean(SEND_FORWARD_FILTER_RAN, false);
        }
    

    配置如下

    zuul:
      routes:
        advice3:
          path: /client/xxx
          url: forward:/b
    
    路由的过程如下

    对于一个请求的处理,是pre,route,post。
    pre以及Post的执行过程也是一样的。只不过执行的过滤器链不一样。

    相关文章

      网友评论

          本文标题:(二)zuul源码-Zuul组件中相关的路由过滤器

          本文链接:https://www.haomeiwen.com/subject/mxcpaltx.html