zoukankan      html  css  js  c++  java
  • Spring Cloud Zuul源码解析

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

      

      

     

  • 相关阅读:
    Python 之解析配置文件模块ConfigParser
    SonarQube代码质量管理平台
    SVN代码统计工具StatSVN
    python 3接口测试
    python+selenium使用chrome时,报错ignore certificate errors
    python3发送邮件(有附件)
    日记
    杂记 包含 serialize().ajaxStart() .ajaxStop()以及其他
    还是要说一下XML。全当日记
    桑心!XML
  • 原文地址:https://www.cnblogs.com/linlf03/p/12603854.html
Copyright © 2011-2022 走看看