温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Springcloud中zuul的Zuul Filter是什么

发布时间:2021-10-19 18:22:14 来源:亿速云 阅读:157 作者:柒染 栏目:大数据

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

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

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

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

    List-1

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

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

    List-2

... @Configuration protected static class ZuulFilterConfiguration {     @Autowired     private Map<String, ZuulFilter> 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<String, ZuulFilter> filters;	private final CounterFactory counterFactory;	private final TracerFactory tracerFactory;	private final FilterLoader filterLoader;	private final FilterRegistry filterRegistry;	public ZuulFilterInitializer(Map<String, ZuulFilter> 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<String, ZuulFilter> entry : this.filters.entrySet()) {	filterRegistry.put(entry.getKey(), entry.getValue());	}	}	@PreDestroy	public void contextDestroyed() {	log.info("Stopping filter initializer");	for (Map.Entry<String, ZuulFilter> 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<ZuulServlet> 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<ZuulServletFilter> 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<ZuulFilter> 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/*的。

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

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI