千家信息网

Springcloud中zuul的Zuul Filter是什么

发表于:2025-02-03 作者:千家信息网编辑
千家信息网最后更新 2025年02月03日,Springcloud中zuul的Zuul Filter是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Spring
千家信息网最后更新 2025年02月03日Springcloud中zuul的Zuul Filter是什么

Springcloud中zuul的Zuul Filter是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

Springcloud的版本是Greenwich.SR2,Springboot版本是2.1.6.release.

最近使用到Springcloud的zuul,分析了下源码,记录下。

如下List-1,我们自己定义的ZuulFilter继承zuul的zuulFilter,之后定义为Bean,交给Spring容器:

List-1

//将过滤器交给Spring管理@Beanpublic AuthFilter authFilter(){    return new AuthFilter();}//xss过滤@Beanpublic XssFilter xssFilter(){    return new XssFilter();}@Beanpublic HelloZuulFilter firewallFilter(){    return new HelloZuulFilter();}@Beanpublic HelloInfoFilter helloInfoFilter(){    return new HelloInfoFilter();}

之后看下ZuulServerAutoConfiguration,如下List-2,@Autowired private Map filters会从Spring容器中获取所有的ZuulFilter,之后实例化ZuulFilterInitializer时,将这个filters传入。

List-2

...@Configurationprotected static class ZuulFilterConfiguration {    @Autowired    private Map filters;    @Bean    public ZuulFilterInitializer zuulFilterInitializer(CounterFactory counterFactory,            TracerFactory tracerFactory) {        FilterLoader filterLoader = FilterLoader.getInstance();        FilterRegistry filterRegistry = FilterRegistry.instance();        return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory,                filterLoader, filterRegistry);    }}...

如下List-3,

  1. FilterRegistry是属性类型,contextInitialized方法上加了@PostConstruct,所以Spring创建这个Bean之后就会调用这个方法,遍历filters之后,放入filterRegistry中,filterRegistry中有个ConcurrentHashMap类型的属性,这些filter就是放入这个ConcurrentHashMap中。

  2. 方法contextDestroyed上加了@PreDestroy注解,之后遍历filters,将其从filterRegistry中移除。

List-3

public class ZuulFilterInitializer {        private static final Log log = LogFactory.getLog(ZuulFilterInitializer.class);        private final Map filters;        private final CounterFactory counterFactory;        private final TracerFactory tracerFactory;        private final FilterLoader filterLoader;        private final FilterRegistry filterRegistry;        public ZuulFilterInitializer(Map filters,                        CounterFactory counterFactory, TracerFactory tracerFactory,                        FilterLoader filterLoader, FilterRegistry filterRegistry) {                this.filters = filters;                this.counterFactory = counterFactory;                this.tracerFactory = tracerFactory;                this.filterLoader = filterLoader;                this.filterRegistry = filterRegistry;        }        @PostConstruct        public void contextInitialized() {                log.info("Starting filter initializer");                TracerFactory.initialize(tracerFactory);                CounterFactory.initialize(counterFactory);                for (Map.Entry entry : this.filters.entrySet()) {                        filterRegistry.put(entry.getKey(), entry.getValue());                }        }        @PreDestroy        public void contextDestroyed() {                log.info("Stopping filter initializer");                for (Map.Entry entry : this.filters.entrySet()) {                        filterRegistry.remove(entry.getKey());                }                clearLoaderCache();                TracerFactory.initialize(null);                CounterFactory.initialize(null);        }...

默认会将ZuulServlet或者ZuulServletFilter注入到Spring容器中,如下如果设置zuul.use-filter为true,那么使用的是ZuulServletFilter,默认没有设置zuul.use-filter,所以使用的是ZuulServlet,如下List-4,ZuulServlet继承了HttpServlet,是个Servlet,之后交给ServletRegistrationBean,将这个ZuulServlet放入到web容器中。

List-4

...@Bean@ConditionalOnMissingBean(name = "zuulServlet")@ConditionalOnProperty(name = "zuul.use-filter", havingValue = "false", matchIfMissing = true)public ServletRegistrationBean zuulServlet() {    ServletRegistrationBean servlet = new ServletRegistrationBean<>(            new ZuulServlet(), this.zuulProperties.getServletPattern());    // The whole point of exposing this servlet is to provide a route that doesn't    // buffer requests.    servlet.addInitParameter("buffer-requests", "false");    return servlet;}@Bean@ConditionalOnMissingBean(name = "zuulServletFilter")@ConditionalOnProperty(name = "zuul.use-filter", havingValue = "true", matchIfMissing = false)public FilterRegistrationBean zuulServletFilter() {    final FilterRegistrationBean filterRegistration = new FilterRegistrationBean<>();    filterRegistration.setUrlPatterns(            Collections.singleton(this.zuulProperties.getServletPattern()));    filterRegistration.setFilter(new ZuulServletFilter());    filterRegistration.setOrder(Ordered.LOWEST_PRECEDENCE);    // The whole point of exposing this servlet is to provide a route that doesn't    // buffer requests.    filterRegistration.addInitParameter("buffer-requests", "false");    return filterRegistration;}...

ZuulServlet的service方法如下,首先会调用preRoute()方法,之后调用route(),最后是postRoute(),preRoute方法调用了zuulRunner.preRoute(),ZuulRunner的preRoute()方法里面调用了FilterProcessor.getInstance().preRoute(),再深入FilterProcessor的preRoute方法,

List-5

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {    try {        this.init((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);        RequestContext context = RequestContext.getCurrentContext();        context.setZuulEngineRan();        try {            this.preRoute();        } catch (ZuulException var13) {            this.error(var13);            this.postRoute();            return;        }        try {            this.route();        } catch (ZuulException var12) {            this.error(var12);            this.postRoute();            return;        }        try {            this.postRoute();        } catch (ZuulException var11) {            this.error(var11);        }    } catch (Throwable var14) {        this.error(new ZuulException(var14, 500, "UNHANDLED_EXCEPTION_" + var14.getClass().getName()));    } finally {        RequestContext.getCurrentContext().unset();    }}void postRoute() throws ZuulException {    this.zuulRunner.postRoute();}void route() throws ZuulException {    this.zuulRunner.route();}void preRoute() throws ZuulException {    this.zuulRunner.preRoute();}

FilterProcessor的preRoute()里面的代码如下List-6,调用runFilters方法,从FilterRegistry取出所有filterType是pre的所有ZuulFilter,之后进行排序,之后逐个调用ZuulFilter的runFilter方法--在方法processZuulFilter里面。ZuulFilter是个抽象类,runFilter方法里面调用了run方法,run方法是抽象方法,由我们自定义实现,如下List-7所示,

List-6

...public void preRoute() throws ZuulException {    try {        this.runFilters("pre");    } catch (ZuulException var2) {        throw var2;    } catch (Throwable var3) {        throw new ZuulException(var3, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + var3.getClass().getName());    }}public Object runFilters(String sType) throws Throwable {    if (RequestContext.getCurrentContext().debugRouting()) {        Debug.addRoutingDebug("Invoking {" + sType + "} type filters");    }    boolean bResult = false;    List list = FilterLoader.getInstance().getFiltersByType(sType);    if (list != null) {        for(int i = 0; i < list.size(); ++i) {            ZuulFilter zuulFilter = (ZuulFilter)list.get(i);            Object result = this.processZuulFilter(zuulFilter);            if (result != null && result instanceof Boolean) {                bResult |= (Boolean)result;            }        }    }    return bResult;}public Object processZuulFilter(ZuulFilter filter) throws ZuulException {    RequestContext ctx = RequestContext.getCurrentContext();    boolean bDebug = ctx.debugRouting();    String metricPrefix = "zuul.filter-";    long execTime = 0L;    String filterName = "";    try {        long ltime = System.currentTimeMillis();        filterName = filter.getClass().getSimpleName();        RequestContext copy = null;        Object o = null;        Throwable t = null;        if (bDebug) {            Debug.addRoutingDebug("Filter " + filter.filterType() + " " + filter.filterOrder() + " " + filterName);            copy = ctx.copy();        }        ZuulFilterResult result = filter.runFilter();        ExecutionStatus s = result.getStatus();        execTime = System.currentTimeMillis() - ltime;        switch(s) {        case FAILED:            t = result.getException();            ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);            break;        case SUCCESS:            o = result.getResult();            ctx.addFilterExecutionSummary(filterName, ExecutionStatus.SUCCESS.name(), execTime);            if (bDebug) {                Debug.addRoutingDebug("Filter {" + filterName + " TYPE:" + filter.filterType() + " ORDER:" + filter.filterOrder() + "} Execution time = " + execTime + "ms");                Debug.compareContextState(filterName, copy);            }        }        if (t != null) {            throw t;        } else {            this.usageNotifier.notify(filter, s);            return o;        }    } catch (Throwable var15) {        if (bDebug) {            Debug.addRoutingDebug("Running Filter failed " + filterName + " type:" + filter.filterType() + " order:" + filter.filterOrder() + " " + var15.getMessage());        }        this.usageNotifier.notify(filter, ExecutionStatus.FAILED);        if (var15 instanceof ZuulException) {            throw (ZuulException)var15;        } else {            ZuulException ex = new ZuulException(var15, "Filter threw Exception", 500, filter.filterType() + ":" + filterName);            ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);            throw ex;        }    }}...

如下List-7所示,用try catch方式来调用run方法,如果run方法抛出异常,则视为失败,将ZuulFilterResult的ExecutionStatus设置为FAILED,所以我们实现的run方法返回什么值并不重要,重要的是不抛出异常,如果抛出异常则视为处理失败。

List-7

public ZuulFilterResult runFilter() {    ZuulFilterResult zr = new ZuulFilterResult();    if (!this.isFilterDisabled()) {        if (this.shouldFilter()) {            Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());            try {                Object res = this.run();                zr = new ZuulFilterResult(res, ExecutionStatus.SUCCESS);            } catch (Throwable var7) {                t.setName("ZUUL::" + this.getClass().getSimpleName() + " failed");                zr = new ZuulFilterResult(ExecutionStatus.FAILED);                zr.setException(var7);            } finally {                t.stopAndLog();            }        } else {            zr = new ZuulFilterResult(ExecutionStatus.SKIPPED);        }    }    return zr;}

要注意的是,上面中涉及到的FilterRegistry引用的都是同一个静态变量,所以各个调用关系见不显示的传递,依然能确保线程安全。

private static final FilterRegistry INSTANCE = new FilterRegistry();

需要注意的是,ZuulServlet和ZuulServletFilter处理的是url为/zuul/*的请求,可以看List-4的this.zuulProperties.getServletPattern(),它的值就是/zuul,之后用ServletRegistration.Dynamic的addMapping方法加上处理的url为/zuul/*的。

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注行业资讯频道,感谢您对的支持。

0