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

本文深入探讨SpringCloudNetflix中Zuul如何利用ThreadLocal管理请求上下文,解析其在过滤器执行过程中的作用,及与InheritableThreadLocal的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.youkuaiyun.com/shang_xs/article/details/87874477
ThreadLocal和InheritableThreadLocal深入探究(一)源码分析
https://blog.youkuaiyun.com/shang_xs/article/details/87889079
ThreadLocal和InheritableThreadLocal深入探究(二)在Spring中的应用
https://blog.youkuaiyun.com/shang_xs/article/details/87889219

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值