Zuul- 呼叫

大軍發表於2020-12-25

ZuulServlet是HttpServlet。Servlet的生命週期包括init(僅第一次)、service、destroy。ZuulServlet的init在Zuul- 啟動提過了,就是建立一個ZuulRunner物件。所以我們主要看service方法

ZuulServlet#service

這個方法就是獲取一個RequestContext,如果沒有則建立,是ThreadLocal類。獲取後就開始呼叫preRoute、route、postRoute、error方法。由於這幾個方法呼叫方式是一致的,所以下面就只講preRoute,這個方法實際就是呼叫ZuulRunner#preRoute方法。

@Override
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
    try {
        // 給RequestContext賦值request和HttpResponse
        init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
        // 獲取RequestContext
        RequestContext context = RequestContext.getCurrentContext();
        context.setZuulEngineRan();

        try {
            preRoute();
        } catch (ZuulException e) {
            error(e);
            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();
    }
}

ZuulRunner#preRoute

preRoute是單例。然後呼叫runFilters。在runFilters中,先從FilterLoader獲取ZuulFilter集合,然後遍歷處理ZuulFilter。

public void preRoute() throws ZuulException {
    runFilters("pre");
    //其他略
}

public Object runFilters(String sType) throws Throwable {
    
    boolean bResult = false;
    // 從FilterLoader獲取ZuulFilter集合
    List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
    if (list != null) {
        for (int i = 0; i < list.size(); i++) {
            ZuulFilter zuulFilter = list.get(i);
            // 處理每個ZuulFilter
            Object result = processZuulFilter(zuulFilter);
            if (result != null && result instanceof Boolean) {
                bResult |= ((Boolean) result);
            }
        }
    }
    return bResult;
}

FilterLoader#getFiltersByType

FilterLoader也是單例。主要就是ConcurrentHashMap型別的hashFiltersByType取值,沒有的話從filterRegistry獲取,然後排序返回。

public List<ZuulFilter> getFiltersByType(String filterType) {
    // 從ConcurrentHashMap型別的hashFiltersByType,透過filterType取ZuulFilter集合
    List<ZuulFilter> list = hashFiltersByType.get(filterType);
    // 如果有了,直接返回
    if (list != null) return list;

    list = new ArrayList<ZuulFilter>();
    //沒有從filterRegistry獲取,並根據filterType拿到對應的ZuulFilter
    Collection<ZuulFilter> filters = filterRegistry.getAllFilters();
    for (Iterator<ZuulFilter> iterator = filters.iterator(); iterator.hasNext(); ) {
        ZuulFilter filter = iterator.next();
        if (filter.filterType().equals(filterType)) {
            list.add(filter);
        }
    }
    // 排序
    Collections.sort(list); // sort by priority

    hashFiltersByType.putIfAbsent(filterType, list);
    return list;
}

FilterProcessor#processZuulFilter

拿到ZuulFilter集合後,對每個ZuulFilter處理。主要的呼叫ZuulFilter的runFilter方法。

public Object processZuulFilter(ZuulFilter filter) throws ZuulException {
    // 其他略    
    ZuulFilterResult result = filter.runFilter();
    // 其他略    
}

ZuulFilter#runFilter

public ZuulFilterResult runFilter() {
    ZuulFilterResult zr = new ZuulFilterResult();
    // 是否配置禁用,"zuul." + this.getClass().getSimpleName() + "." + filterType() + ".disable"
    // 比如zuul.PreDecorationFilter.pre.disable=false
    if (!isFilterDisabled()) {
        // 這個是我們需要寫的,是否過濾
        if (shouldFilter()) {
            Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());
            try {
                // 這個是我們需要寫的run方法
                Object res = run();
                zr = new ZuulFilterResult(res, ExecutionStatus.SUCCESS);
            } catch (Throwable e) {
                t.setName("ZUUL::" + this.getClass().getSimpleName() + " failed");
                zr = new ZuulFilterResult(ExecutionStatus.FAILED);
                zr.setException(e);
            } finally {
                t.stopAndLog();
            }
        } else {
            zr = new ZuulFilterResult(ExecutionStatus.SKIPPED);
        }
    }
    return zr;
}

總結

ZuulServlet#service中,透過各個ZuulServlet進行相關處理。
image

相關文章