Zuul【工作原理】


zuul的核心邏輯都是由一系列filter過濾器鏈實現的,但是filter的類型不同,執行的時機也不同,效果自然也不一樣,主要特點如下:

  1. filter的類型:filter的類型,決定了它在整個filter鏈中的執行順序,可能在端點路由前執行,也可能在端點路由時執行,還有可能在端點路由后執行,甚至是端點路由發生異常時執行。
  2. filter的執行順序:同一種類型的filter,可以通過filterOrder()方法設置執行順序,一般都是根據業務場景自定義filter執行順序。
  3. filter執行條件:filter運行所需的標准,或條件。
  4. filter執行效果:符合某個filter執行條件,產生執行效果。

zuul內部有一套完整的機制,可以動態讀取編譯運行filter機制,filter與filter之間不直接通信,在請求線程中會通過RequestContext來共享狀態,它內部是用ThreadLocal實現的,例如HttpServletRequest、HttpServletResponse、異常信息等。部分源碼如下:

public class RequestContext extends ConcurrentHashMap<String, Object> {

    private static final Logger LOG = LoggerFactory.getLogger(RequestContext.class);

    protected static Class<? extends RequestContext> contextClass = RequestContext.class;

    private static RequestContext testContext = null;

    protected static final ThreadLocal<? extends RequestContext> threadLocal = new ThreadLocal<RequestContext>() { @Override protected RequestContext initialValue() { try { return contextClass.newInstance(); } catch (Throwable e) { throw new RuntimeException(e); } } };

  //.......
}

zuul中不同類型的filter執行邏輯的核心在ZuulServlet類中,主要代碼如下:

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 { init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); // Marks this request as having passed through the "Zuul engine", as opposed to servlets // explicitly bound in web.xml, for which requests will not have the same data attached
            RequestContext context = RequestContext.getCurrentContext(); context.setZuulEngineRan(); try { preRoute(); //如果preRoute方法在執行的時候出現異常,直接就拋出500異常,不會走catch中的error方法,見下圖FilterProcessor類中的preRoute方法。 } catch (ZuulException e) { error(e); //如果preRoute在執行過程中,拋出Zuul異常,這里被捕捉到以后,會執行error方法,打印堆棧信息,見下圖FilterProcessor類中的error方法。 postRoute(); return; } try { route(); } catch (ZuulException e) { error(e); postRoute(); return; } try { postRoute(); } catch (ZuulException e) { error(e); return; } } catch (Throwable e) { error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName())); } finally { RequestContext.getCurrentContext().unset(); } }

  //....... }

 

 

 

 

 

zuul一共有4種不同的生命周期:

  1. pre:在zuul網關按照規則路由到下級服務之前執行,如果需要對請求進行預處理,可以使用這種類型的過濾器。如:認證鑒權,限流等。
  2. route:這種過濾器是zuul路由動作的執行者,是Apache HttpClient或Ribbon構建和發送原始HTTP請求的地方,現在也支持OKHTTP。
  3. post:這種過濾器是在端點請求完畢,返回結果或者發生異常后執行的filter。如果需要對返回的結果進行再次處理,可以在這種過濾中處理邏輯。
  4. error: 這種過濾器是在整個生命周期內,如果發生異常,就執行該filter,可以做全局異常處理。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM