work hard work smart

专注于Java后端开发。 不断总结,举一反三。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Spring Cloud Zuul源码解析

Posted on 2020-03-31 12:29  work hard work smart  阅读(216)  评论(0编辑  收藏  举报

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);
	}