Springcloud中zuul的Zuul Filter是什么,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。
創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿(mǎn)足客戶(hù)于互聯(lián)網(wǎng)時(shí)代的麻章網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
Springcloud的版本是Greenwich.SR2,Springboot版本是2.1.6.release.
最近使用到Springcloud的zuul,分析了下源碼,記錄下。
如下List-1,我們自己定義的ZuulFilter繼承zuul的zuulFilter,之后定義為Bean,交給Spring容器:
List-1
//將過(guò)濾器交給Spring管理 @Bean public AuthFilter authFilter(){ return new AuthFilter(); } //xss過(guò)濾 @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會(huì)從Spring容器中獲取所有的ZuulFilter,之后實(shí)例化ZuulFilterInitializer時(shí),將這個(gè)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,
FilterRegistry是屬性類(lèi)型,contextInitialized方法上加了@PostConstruct,所以Spring創(chuàng)建這個(gè)Bean之后就會(huì)調(diào)用這個(gè)方法,遍歷filters之后,放入filterRegistry中,filterRegistry中有個(gè)ConcurrentHashMap類(lèi)型的屬性,這些filter就是放入這個(gè)ConcurrentHashMap中。
方法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); } ...
默認(rèn)會(huì)將ZuulServlet或者ZuulServletFilter注入到Spring容器中,如下如果設(shè)置zuul.use-filter為true,那么使用的是ZuulServletFilter,默認(rèn)沒(méi)有設(shè)置zuul.use-filter,所以使用的是ZuulServlet,如下List-4,ZuulServlet繼承了HttpServlet,是個(gè)Servlet,之后交給ServletRegistrationBean,將這個(gè)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方法如下,首先會(huì)調(diào)用preRoute()方法,之后調(diào)用route(),最后是postRoute(),preRoute方法調(diào)用了zuulRunner.preRoute(),ZuulRunner的preRoute()方法里面調(diào)用了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,調(diào)用runFilters方法,從FilterRegistry取出所有filterType是pre的所有ZuulFilter,之后進(jìn)行排序,之后逐個(gè)調(diào)用ZuulFilter的runFilter方法——在方法processZuulFilter里面。ZuulFilter是個(gè)抽象類(lèi),runFilter方法里面調(diào)用了run方法,run方法是抽象方法,由我們自定義實(shí)現(xiàn),如下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方式來(lái)調(diào)用run方法,如果run方法拋出異常,則視為失敗,將ZuulFilterResult的ExecutionStatus設(shè)置為FAILED,所以我們實(shí)現(xiàn)的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引用的都是同一個(gè)靜態(tài)變量,所以各個(gè)調(diào)用關(guān)系見(jiàn)不顯示的傳遞,依然能確保線程安全。
private static final FilterRegistry INSTANCE = new FilterRegistry();
需要注意的是,ZuulServlet和ZuulServletFilter處理的是url為/zuul/*的請(qǐng)求,可以看List-4的this.zuulProperties.getServletPattern(),它的值就是/zuul,之后用ServletRegistration.Dynamic的addMapping方法加上處理的url為/zuul/*的。
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)的支持。
文章題目:Springcloud中zuul的ZuulFilter是什么
本文地址:http://aaarwkj.com/article14/ispsge.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站、網(wǎng)站營(yíng)銷(xiāo)、軟件開(kāi)發(fā)、網(wǎng)站建設(shè)、品牌網(wǎng)站建設(shè)、域名注冊(cè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)