ZuulServlet源码分析及ZuulFilter加载


参考
https://yq.aliyun.com/wenji/2...
https://blog.csdn.net/lds2227...

1.声明ZuulServlet

@Configuration @EnableConfigurationProperties({ZuulProperties.class}) @ConditionalOnClass(ZuulServlet.class)  --->[ConditionalOnClass详解](https://412887952-qq-com.iteye.com/blog/2395065)
@Import(ServerPropertiesAutoConfiguration.class) public class ZuulConfigurationCustom { @Autowired protected ZuulProperties zuulProperties; @Bean @ConditionalOnMissingBean(name = "zuulServlet") 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; } }

以上通过 ServletRegistrationBean servlet = new ServletRegistrationBean(new ZuulServlet(),this.zuulProperties.getServletPattern()); 使用配置的URL mapping实例化一个Servlet,其中URL mapping在 application.properties 文件中配置,例如:

#拦截路径 zuul.servletPath=/openapi/

以上实现了 /openapi/ 被 ZuulServlet 处理的逻辑。

2.ZuulServlet处理逻辑

当请求path为 /openapi/ 的请求进入网关后,就会被 ZuulServlet 处理,以下为 ZuulServlet 处理流程:

public class ZuulServlet extends HttpServlet { private static final long serialVersionUID = -3374242278843351500L; private ZuulRunner zuulRunner; //ZuulServlet逻辑真正的实现类
 @Override public void init(ServletConfig config) throws ServletException { super.init(config); String bufferReqsStr = config.getInitParameter("buffer-requests"); boolean bufferReqs = bufferReqsStr != null && bufferReqsStr.equals("true") ? true : false; zuulRunner = new ZuulRunner(bufferReqs); } @Override public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException { try { init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);//将servletRequest和servletResponse存入RequestContext(RequestContext.getCurrentContext()) // Marks this request as having passed through the "Zuul engine", as opposed to servlets // explicitly bound in web.xml, for which requests will not have the same data attached
            RequestContext context = RequestContext.getCurrentContext(); context.setZuulEngineRan(); try { preRoute(); } catch (ZuulException e) { error(e); postRoute(); return; } try { route(); } catch (ZuulException e) { error(e); postRoute(); return; } try { postRoute(); } catch (ZuulException e) { error(e); return; } } catch (Throwable e) { error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName())); } finally { RequestContext.getCurrentContext().unset(); } } /** * executes "post" ZuulFilters * * @throws ZuulException */
    void postRoute() throws ZuulException { zuulRunner.postRoute(); } /** * executes "route" filters * * @throws ZuulException */
    void route() throws ZuulException { zuulRunner.route(); } /** * executes "pre" filters * * @throws ZuulException */
    void preRoute() throws ZuulException { zuulRunner.preRoute(); } /** * initializes request * * @param servletRequest * @param servletResponse */
    void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) { zuulRunner.init(servletRequest, servletResponse); } /** * sets error context info and executes "error" filters * * @param e */
    void error(ZuulException e) { RequestContext.getCurrentContext().setThrowable(e); zuulRunner.error(); } }
View Code

以上 service() 方法中 init() 会在ZuulRunner中将 servletRequest 和 servletResponse 存入 RequestContext(RequestContext.getCurrentContext()) ,如下:

public void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) { RequestContext ctx = RequestContext.getCurrentContext(); if (bufferRequests) { ctx.setRequest(new HttpServletRequestWrapper(servletRequest)); } else { ctx.setRequest(servletRequest); } ctx.setResponse(new HttpServletResponseWrapper(servletResponse)); }

 ZuulServlet 的 preRoute() 方法通过 zuulRunner 的 preRoute() 实现; zuulRunner 的 preRoute() 通过调用 FilterProcessor.getInstance().preRoute() 实现; FilterProcessor 的 preRoute() 执行自身 runFilters("pre") 方法执行 prefilter ; runFilters("pre") 方法会从 FilterLoader.getInstance().getFiltersByType(sType) 中过滤出pre filter循环执行 processZuulFilter(zuulFilter) ,以下为服务调用层次关系。

ZuulServlet.preRoute(); |_____ zuulRunner.preRoute(); |_____ FilterProcessor.getInstance().preRoute(); |_____ runFilters("pre"); |_____ List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType); |       |_____ Collection<ZuulFilter> filters = filterRegistry.getAllFilters(); |_____ processZuulFilter(zuulFilter); |_____ ZuulFilterResult result = filter.runFilter();//执行filter,其中包括filter是否需要执行(shouldFilter()) //filterRegistry为单例模式,通过FilterRegistry.instance()获取实例,getAllFilters()方法获取类型为ConcurrentHashMap<String, ZuulFilter>的filters。

3.ZuulFilter 加载

针对上述代码中的 FilterRegistry 中的filters需要在项目启动时,显示声明进行初始化:

 @Configuration protected static class ZuulFilterConfiguration { //按类型将所有ZuulFilter注入到map中
 @Autowired private Map<String, ZuulFilter> filters; @Bean public ZuulFilterInitializer zuulFilterInitializer() { return new ZuulFilterInitializer(this.filters); //将项目中的ZuulFilter存入FilterRegistry.instance()的filters中
 } }

其中 ZuulFilterInitializer 为实现了 ServletContextListener 类,会根据项目声明在项目启动时进行对 FilterRegistry.instance() 的 filters 进行初始化。

@CommonsLog public class ZuulFilterInitializer implements ServletContextListener { private Map<String, ZuulFilter> filters; public ZuulFilterInitializer(Map<String, ZuulFilter> filters) { this.filters = filters; } @Override public void contextInitialized(ServletContextEvent sce) { log.info("Starting filter initializer context listener"); // FIXME: mocks monitoring infrastructure as we don't need it for this simple app
 MonitoringHelper.initMocks(); FilterRegistry registry = FilterRegistry.instance(); for (Map.Entry<String, ZuulFilter> entry : this.filters.entrySet()) { registry.put(entry.getKey(), entry.getValue()); } } ..........后继代码省略 }

4.其他

 ZuulServlet 的 route() 、 postRoute() 、 error(e) 方法执行逻辑与 preRoute() 相同。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM