SpringCloudZuul源码解析-2

Zuul如何继承SpringmMvc

  1. ZuulHandlerMapping此类实现了 springmvc AbstractUrlHandlerMapping 重写了
    lookupHandler方法并在此方法中 完成了 路由信息的 注册

  2. ZuulHandlerMapping 源码分析
    该类主要作用完成了 zuul 路由的注册 多个 path配置对应一个 ZuulController
    比如 application.yml 配置了 2个route 的path 对应过来的就是

/test01/** --->ZuulController
/test02/** ---->ZuulController
zuul:
  ignored-patterns: /test/**
  routes:
    myroute:
      url: http://localhost:8085/
      path: /test01/**
      id: test
    myroute1:
      url: http://localhost:8080/
      path: /test02/**
      id: test-1
public class ZuulHandlerMapping extends AbstractUrlHandlerMapping {
	private final RouteLocator routeLocator;
	private final ZuulController zuul;
	private ErrorController errorController;
	private PathMatcher pathMatcher = new AntPathMatcher();
	private volatile boolean dirty = true;
	public ZuulHandlerMapping(RouteLocator routeLocator, ZuulController zuul) {
		this.routeLocator = routeLocator;
		this.zuul = zuul;
		//设置handlerMapper的顺序为-200 也就是最前
		//很重要在DispatcherServlet中 doDispatch中 getHandler会体现出来
		setOrder(-200);
	}

    //跨越相关 重写了父类方法判断CorsConfiguration是否为空
	@Override
	protected HandlerExecutionChain getCorsHandlerExecutionChain(
			HttpServletRequest request, HandlerExecutionChain chain,
			CorsConfiguration config) {
		if (config == null) {
			return chain;
		}
		return super.getCorsHandlerExecutionChain(request, chain, config);
	}

	public void setErrorController(ErrorController errorController) {
		this.errorController = errorController;
	}
	
	//设置路由注册标志 为true需要注册
	public void setDirty(boolean dirty) {
		this.dirty = dirty;
		if (this.routeLocator instanceof RefreshableRouteLocator) {
			((RefreshableRouteLocator) this.routeLocator).refresh();
		}
	}

	//重写的父类的 查询 handler方法
	
   /* 1,判断是否为 error的url如果是并且errorController存在 返回null
    * 2,判断 zuul.ignored-patterns配置 如果匹配到直接返回null
	* 3,判断是否为重定向 如果为重定向 返回null
	*/
	@Override
	protected Object lookupHandler(String urlPath, HttpServletRequest request)
			throws Exception {
		if (this.errorController != null
				&& urlPath.equals(this.errorController.getErrorPath())) {
			return null;
		}
		if (isIgnoredPath(urlPath, this.routeLocator.getIgnoredPaths())) {
			return null;
		}
		RequestContext ctx = RequestContext.getCurrentContext();
		if (ctx.containsKey("forward.to")) {
			return null;
		}
		//判断路由是注册过
		if (this.dirty) {
			synchronized (this) {
				if (this.dirty) {
				    //注册handler
					registerHandlers();
					this.dirty = false;
				}
			}
		}
		return super.lookupHandler(urlPath, request);
	}   
    //处理zuul.ignored-patterns配置的url是否匹配
	private boolean isIgnoredPath(String urlPath, Collection<String> ignored) {
		if (ignored != null) {
			for (String ignoredPath : ignored) {
				if (this.pathMatcher.match(ignoredPath, urlPath)) {
					return true;
				}
			}
		}
		return false;
	}
   //注册handler
	private void registerHandlers() {
		Collection<Route> routes = this.routeLocator.getRoutes();
		if (routes.isEmpty()) {
			this.logger.warn("No routes found from RouteLocator");
		}
		else {
			for (Route route : routes) {
			//key 为route的 path
			//value为 ZuulController
				registerHandler(route.getFullPath(), this.zuul);
			}
		}
	}
}
  1. ZuulController 核心类分析 上面分析 得知所有的 url 都对应一个 controller 那就是 ZuulController
    类图:
    ZuulContoller类图关系
    实现了ServletWrappingController类 见名知意 其实就是一个 Servlet 持有器的 Controller 实现了 Controller接口
public class ZuulController extends ServletWrappingController {

	public ZuulController() {
		//调用夫类方法 设置servlet的class父类通过反射创建对象
		setServletClass(ZuulServlet.class);
		//设置servlet名称
		setServletName("zuul");
		setSupportedMethods((String[]) null);
	}

	@Override
	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		try {
		//调用夫类方法 处理请求
			return super.handleRequestInternal(request, response);
		}
		finally {
			//因为zuul中RequestContext 使用 threadLocal存储请求结束后 需要remove 释放 防止内存泄露
			RequestContext.getCurrentContext().unset();
		}
	}

}

父类 ServletWrappingController 的handleRequestInternal() 方法

	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		//servlet非空判断
		Assert.state(this.servletInstance != null, "No Servlet instance");
		//直接调用servlet service方法 也就是 ZuulServlet 的service方法
		this.servletInstance.service(request, response);
		return null;
	}
  1. ZuulSevlet 继承 HttpServlet
public class ZuulServlet extends HttpServlet {

    private static final long serialVersionUID = -3374242278843351500L;
    private ZuulRunner zuulRunner;


    @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 {
        	//请求进来之后 zuulRunner初始化 主要是创建RequestContext对象
            init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);

            RequestContext context = RequestContext.getCurrentContext();
    		//设置zuulEngineRan 属性为true
            context.setZuulEngineRan();

            try {
            //执行 pre 过滤器
                preRoute();
            } catch (ZuulException e) {
            //出现异常  执行error后 再执行 postRoute
                error(e);
                postRoute();
                return;
            }
            try {
            //执行route
                route();
            } catch (ZuulException e) {
                error(e);
                postRoute();
                return;
            }
            try {
            //执行postRoute
                postRoute();
            } catch (ZuulException e) {
                error(e);
                return;
            }

        } catch (Throwable e) {
        	//出现异常调用error过滤器
            error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
        } finally {
        //释放内存
            RequestContext.getCurrentContext().unset();
        }
    }

    /**
     * 执行 "post" 过滤器
     */
    void postRoute() throws ZuulException {
        zuulRunner.postRoute();
    }

    /**
     * 执行 "route" 类型过滤器
     */
    void route() throws ZuulException {
        zuulRunner.route();
    }

    /**
     * 执行 "pre" 类型过滤器
     */
    void preRoute() throws ZuulException {
        zuulRunner.preRoute();
    }

   	//初始化 zuulRunner 创建 RequestContext对象并把请求对象和返回对象进行设置
    void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
        zuulRunner.init(servletRequest, servletResponse);
    }

	//发生错误
    void error(ZuulException e) {
        RequestContext.getCurrentContext().setThrowable(e);
        zuulRunner.error();
    }
}
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值