Zuul 處理 Http 請求都是基於 SpringMVC 上的,細心的你必定注意到了,當你搭建了一個zuul後配置後端隱射請求 /apps/** 到你的後端服務時,不管 /apps/**** 仍是 /zuul/apps/**** 都能到達你的後端服務。java
那麼這到達是如何實現的呢?web
Zuul 有一個自制的 Servlet -- ZuulServlet, 它包含了 Zuul 全部的處理流程的主幹支,這裏不詳細介紹,之後會篇章會詳細介紹 Zuul 的處理流程。後端
SpringBoot 有個 ServletRegistrationBean 是專門用來註冊自定義 Servlet 的。api
public ServletRegistrationBean zuulServlet() { ServletRegistrationBean servlet = new ServletRegistrationBean(new ZuulServlet(), this.zuulProperties.getServletPattern()); servlet.addInitParameter("buffer-requests", "false"); return servlet; }
這裏還有一個定義路基path 的使用,默認是 /zuul,你能夠經過配置文件定義成其餘,以下就改爲 /api 了app
zuul.servletPath=/api
若是沒有使用 SpringBoot 的話,那麼其實老辦法只要將 ZuulServlet 配置在 web.xml 中便可,路徑也是 web.xml 中配置。ide
來看下這個是哪門哪派的。this
RequestMappingHandlerMapping 不會陌生,SpringMVC默認使用的就是這個,它會捕捉全部 @Controller 和 @RequetMapping 註解的方法來處理不一樣的URL。spa
SpringMVC3.1以前其實不是使用上面這個類,而是使用 AbstractUrlHandlerMapping 的派系 -- DefaultAnnotationHandlerMapping,這個類但是 ZuulHandlerMapping 一個派系的,都是根據 URL 來選擇使用使用什麼來處理。.net
那到底用什麼來處理呢?ZuulHandlerMapping 中 registerHandlers 方法回答了這個問題code
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) { registerHandler(route.getFullPath(), this.zuul); } } }
this.zuul 是什麼? ZuulController
public class ZuulController extends ServletWrappingController
原來是 Servlet 包裝成 Controller, 其實仍是 ZuulServlet
public class ZuulController extends ServletWrappingController { public ZuulController() { setServletClass(ZuulServlet.class); // <<======= See Here! setServletName("zuul"); setSupportedMethods((String[]) null); // Allow all } @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { try { return super.handleRequestInternal(request, response); } finally { RequestContext.getCurrentContext().unset(); } } }
Zuul 的 Request 怎麼進來的到這已經清楚了,下面分析進來之後發生了什麼。
詳細代碼解析見 SpringCloud 之 Zuul 源代碼詳細筆記