ThreadLocal和InheritableThreadLocal深入探究(三)在Spring Cloud Netflix中的应用

ThreadLocal和InheritableThreadLocal深入探究(三)在Spring Cloud Netflix中的应用

ThreadLocalSpring Cloud Netflix 中的实现:

com.netflix.zuul.context.RequestContext

请求上下文包含请求、响应、状态信息和数据, 以便 ZuulFilters 访问和共享。在请求的持续时间内, 请求上下文处于 “线程本地” 的基础上。可以通过设置上下文类替换请求上下文的扩展。这里的大多数方法都是方便包装的方法,请求上下文是并发哈希图的扩展。

The Request Context holds request, response,  state information and data for ZuulFilters to access and share The RequestContext lives for the duration of the request and is ThreadLocal.extensions of RequestContext can be substituted by setting the contextClass Most methods here are convenience wrapper methods; the RequestContext is an extension of a ConcurrentHashMap

该类暴露支持了Spring Cloud Netflix中对ZuulServletFilter的支持,在如下代码中具体实现:

源码分析

public class RequestContext extends ConcurrentHashMap<String, Object> {
    protected static Class<? extends RequestContext> contextClass = RequestContext.class;

    private static RequestContext testContext = null;
	// 定义ThreadLocal
    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);
            }
        }
    };
    // 获得请求上下文
    public static RequestContext getCurrentContext() {
        if (testContext != null) return testContext;

        RequestContext context = threadLocal.get();
        return context;
    }
}
// Filter执行器
public class FilterProcessor {
    // 筛选过滤器,并进行路由调用,异常时使用500状态代码抛出 zuulexception
    public void postRoute() throws ZuulException {
        try {
            runFilters("post");
        } catch (ZuulException e) {
            throw e;
        } catch (Throwable e) {
            throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_POST_FILTER_" + e.getClass().getName());
        }
    }
    
// 执行所有Filter,包括自定义Filter
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 = list.get(i);
                Object result = processZuulFilter(zuulFilter);
                if (result != null && result instanceof Boolean) {
                    bResult |= ((Boolean) result);
                }
            }
        }
        return bResult;
    }
    ...
}
// servlet 过滤器中运行 zuul 过滤器。首先调用路由前过滤器,
// 后发布路过滤器。处理了预路由和路由中的异常过滤器, 然后调用异常过滤器
public class ZuulServletFilter implements Filter {
@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try {
            init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
            try {
                preRouting();
            } catch (ZuulException e) {
                error(e);
                postRouting();
                return;
            }
            
            // Only forward onto to the chain if a zuul response is not being sent
            if (!RequestContext.getCurrentContext().sendZuulResponse()) {
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
            
            try {
                routing();
            } catch (ZuulException e) {
                error(e);
                postRouting();
                return;
            }
            try {
                postRouting();
            } catch (ZuulException e) {
                error(e);
                return;
            }
        } catch (Throwable e) {
            error(new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_FROM_FILTER_" + e.getClass().getName()));
        } finally {
            RequestContext.getCurrentContext().unset();
        }
    }
    ...
}

总结

经过对Spring Cloud Netflix源码的分析,我们得出在spring-cloud-netflix-zuul中对于ThreadLocal父子类继承关系的动态设置,以及调用、实现。与Spring中的区别是在于设计不同,

该处的设计只是采用ThreadLocal,没有使用InheritableThreadLocal,所以在子线程中不能获取父请求上下文中的属性值。

最后,该设计的对比也表现了Spring Framework的优秀之处。

相关文章推荐

ThreadLocal深入理解与内存泄漏分析
https://blog.csdn.net/shang_xs/article/details/87874477
ThreadLocal和InheritableThreadLocal深入探究(一)源码分析
https://blog.csdn.net/shang_xs/article/details/87889079
ThreadLocal和InheritableThreadLocal深入探究(二)在Spring中的应用
https://blog.csdn.net/shang_xs/article/details/87889219

你可能感兴趣的:(java)