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; } } }
3)ZuulFilterResult result = filter.runFilter(); 这里使用的是ZuulFilter.runFilter()
public ZuulFilterResult runFilter() { ZuulFilterResult zr = new ZuulFilterResult(); if (!this.isFilterDisabled()) { if (this.shouldFilter()) { Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName()); try { // 关键是这句。这里的实现类为RibbonRoutingFilter,下面详细介绍RibbonRoutingFilter.run方法 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; }
4)RibbonRoutingFilter.run方法
RibbonRoutingFilter:使用Ribbon、Hystrix和可插入的http客户端发送请求
@Override public Object run() { RequestContext context = RequestContext.getCurrentContext(); this.helper.addIgnoredHeaders(); try { RibbonCommandContext commandContext = buildCommandContext(context); //关键是这里 ClientHttpResponse response = forward(commandContext); setResponse(response); return response; } catch (ZuulException ex) { throw new ZuulRuntimeException(ex); } catch (Exception ex) { throw new ZuulRuntimeException(ex); } } //forward方法 protected ClientHttpResponse forward(RibbonCommandContext context) throws Exception { Map<String, Object> info = this.helper.debug(context.getMethod(), context.getUri(), context.getHeaders(), context.getParams(), context.getRequestEntity()); RibbonCommand command = this.ribbonCommandFactory.create(context); try { //关键是这里,command的实现类为HystrixCommand ClientHttpResponse response = command.execute(); this.helper.appendDebug(info, response.getRawStatusCode(), response.getHeaders()); return response; } catch (HystrixRuntimeException ex) { return handleException(info, ex); } } //HystrixCommand.execute() public R execute() { try { //关键是这里 return this.queue().get(); } catch (Exception var2) { throw Exceptions.sneakyThrow(this.decomposeException(var2)); } }
总结: 最终Zuul调用的是HystrixCommand进行转发到各个服务中去。
4、SimpleHostRoutingFilter:简单路由,通过HttpClient向预定的URL发送请求
@Override public Object run() { RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest request = context.getRequest(); MultiValueMap<String, String> headers = this.helper .buildZuulRequestHeaders(request); MultiValueMap<String, String> params = this.helper .buildZuulRequestQueryParams(request); String verb = getVerb(request); InputStream requestEntity = getRequestBody(request); if (getContentLength(request) < 0) { context.setChunkedRequestBody(); } String uri = this.helper.buildZuulRequestURI(request); this.helper.addIgnoredHeaders(); try { //关键在这里 CloseableHttpResponse response = forward(this.httpClient, verb, uri, request, headers, params, requestEntity); setResponse(response); } catch (Exception ex) { throw new ZuulRuntimeException(handleException(ex)); } return null; } //forward private CloseableHttpResponse forward(CloseableHttpClient httpclient, String verb, String uri, HttpServletRequest request, MultiValueMap<String, String> headers, MultiValueMap<String, String> params, InputStream requestEntity) throws Exception { Map<String, Object> info = this.helper.debug(verb, uri, headers, params, requestEntity); URL host = RequestContext.getCurrentContext().getRouteHost(); HttpHost httpHost = getHttpHost(host); uri = StringUtils.cleanPath( MULTIPLE_SLASH_PATTERN.matcher(host.getPath() + uri).replaceAll("/")); long contentLength = getContentLength(request); ContentType contentType = null; if (request.getContentType() != null) { contentType = ContentType.parse(request.getContentType()); } InputStreamEntity entity = new InputStreamEntity(requestEntity, contentLength, contentType); HttpRequest httpRequest = buildHttpRequest(verb, uri, entity, headers, params, request); try { log.debug(httpHost.getHostName() + " " + httpHost.getPort() + " " + httpHost.getSchemeName()); //关键在这里 CloseableHttpResponse zuulResponse = forwardRequest(httpclient, httpHost, httpRequest); this.helper.appendDebug(info, zuulResponse.getStatusLine().getStatusCode(), revertHeaders(zuulResponse.getAllHeaders())); return zuulResponse; } finally { // When HttpClient instance is no longer needed, // shut down the connection manager to ensure // immediate deallocation of all system resources // httpclient.getConnectionManager().shutdown(); } } //forwardRequest private CloseableHttpResponse forwardRequest(CloseableHttpClient httpclient, HttpHost httpHost, HttpRequest httpRequest) throws IOException { return httpclient.execute(httpHost, httpRequest); }