1、@EnableZuulProxy注解
通过前面Zull的使用可知,需要增加@EnableZuulProxy注解
@EnableCircuitBreaker @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(ZuulProxyMarkerConfiguration.class) public @interface EnableZuulProxy { }
Import了ZuulProxyMarkerConfiguration,
/** * Responsible for adding in a marker bean to trigger activation of * {@link ZuulProxyAutoConfiguration}. * * @author Biju Kunjummen */ @Configuration(proxyBeanMethods = false) public class ZuulProxyMarkerConfiguration { @Bean public Marker zuulProxyMarkerBean() { return new Marker(); } class Marker { } }
从注释里可知,ZuulProxyMarkerConfiguration的作用是负责增加一个marker bean去激活ZuulProxyAutoConfiguration。下面介绍下ZuulProxyAutoConfiguration
2、ZuulProxyAutoConfiguration
@Configuration(proxyBeanMethods = false) @EnableConfigurationProperties({ ZuulProperties.class }) @ConditionalOnClass({ ZuulServlet.class, ZuulServletFilter.class }) @ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class) public class ZuulServerAutoConfiguration { ... //组合路由定位器, @Bean @Primary public CompositeRouteLocator primaryRouteLocator( Collection<RouteLocator> routeLocators) { return new CompositeRouteLocator(routeLocators); } //默认的路由定位器,主要负责维护配置文件中的路由配置。 @Bean @ConditionalOnMissingBean(SimpleRouteLocator.class) public SimpleRouteLocator simpleRouteLocator() { return new SimpleRouteLocator(this.server.getServlet().getContextPath(), this.zuulProperties); } //ZuulController: Zuul创建一个Controller,用户将请求交由ZuulServlet处理 @Bean public ZuulController zuulController() { return new ZuulController(); } //ZuulHandlerMapping: 这个会添加到SpringMVC的handleMapping链中, //只有选择了ZuulHandlerMapping的请求才会才能触发到Zuul的后续流程 @Bean public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes, ZuulController zuulController) { ZuulHandlerMapping mapping = new ZuulHandlerMapping(routes, zuulController); mapping.setErrorController(this.errorController); mapping.setCorsConfigurations(getCorsConfigurations()); return mapping; } @Bean @ConditionalOnMissingBean(name = "zuulServlet") @ConditionalOnProperty(name = "zuul.use-filter", havingValue = "false", matchIfMissing = true) public ServletRegistrationBean zuulServlet() { //当没有ZuulServlet,会构造一个ZuulServlet,下面详细介绍下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; } ... }
3、ZuulServlet源码解析
ZuulServlet是这个流程的核心
public class ZuulServlet extends HttpServlet { private static final long serialVersionUID = -3374242278843351500L; private ZuulRunner zuulRunner; public ZuulServlet() { } public void init(ServletConfig config) throws ServletException { super.init(config); String bufferReqsStr = config.getInitParameter("buffer-requests"); boolean bufferReqs = bufferReqsStr != null && bufferReqsStr.equals("true"); //1、创建ZuulRunner对象。下面介绍zuulRunner this.zuulRunner = new ZuulRunner(bufferReqs); } public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { try { this.init((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse); RequestContext context = RequestContext.getCurrentContext(); context.setZuulEngineRan(); try { //执行pre阶段的filters this.preRoute(); } catch (ZuulException var12) { this.error(var12); this.postRoute(); return; } try { //执行route阶段的filters this.route(); } catch (ZuulException var13) { this.error(var13); this.postRoute(); return; } try { //执行post阶段的filters 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 { //通过zuulRunner调用后置处理 this.zuulRunner.postRoute(); } void route() throws ZuulException { this.zuulRunner.route(); } void preRoute() throws ZuulException { this.zuulRunner.preRoute(); } void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) { this.zuulRunner.init(servletRequest, servletResponse); } void error(ZuulException e) { RequestContext.getCurrentContext().setThrowable(e); this.zuulRunner.error(); } }
1)ZuulRunner
public class ZuulRunner { private boolean bufferRequests; public ZuulRunner() { this.bufferRequests = true; } public ZuulRunner(boolean bufferRequests) { this.bufferRequests = bufferRequests; } public void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) { RequestContext ctx = RequestContext.getCurrentContext(); if (this.bufferRequests) { ctx.setRequest(new HttpServletRequestWrapper(servletRequest)); } else { ctx.setRequest(servletRequest); } ctx.setResponse(new HttpServletResponseWrapper(servletResponse)); } public void postRoute() throws ZuulException { FilterProcessor.getInstance().postRoute(); } public void route() throws ZuulException { FilterProcessor.getInstance().route(); } public void preRoute() throws ZuulException { FilterProcessor.getInstance().preRoute(); } public void error() { FilterProcessor.getInstance().error(); } }
最终调用的是FilterProcessor
2)FilterProcessor
public class FilterProcessor { public void postRoute() throws ZuulException { try { //调用runFilters方法 this.runFilters("post"); } catch (ZuulException var2) { throw var2; } catch (Throwable var3) { throw new ZuulException(var3, 500, "UNCAUGHT_EXCEPTION_IN_POST_FILTER_" + var3.getClass().getName()); } } public void route() throws ZuulException { try { this.runFilters("route"); } catch (ZuulException var2) { throw var2; } catch (Throwable var3) { throw new ZuulException(var3, 500, "UNCAUGHT_EXCEPTION_IN_ROUTE_FILTER_" + var3.getClass().getName()); } } 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); //关键是这个processZuulFilter方法 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; } } }