Spring何时清除Baggage上下文?如何调整过滤器执行时机?
问题分析与解决方案
为什么加@Order(Ordered.HIGHEST_PRECEDENCE)会拿不到BaggageField的id?
过滤器的执行遵循「先按优先级从高到低执行前置逻辑,请求处理完成后再按优先级从低到高执行后置逻辑(即filterChain.doFilter之后的代码)」的规则。
当你给CollectionFilter设置最高优先级时,执行顺序是这样的:
- 你的过滤器先执行前置逻辑
- 调用
filterChain.doFilter,触发后续所有过滤器(包括Brave的TraceFilter)的前置逻辑——TraceFilter会在这里初始化trace上下文 - 执行Controller等业务逻辑,设置BaggageField的
id - 按优先级从低到高执行后置逻辑:先执行其他低优先级过滤器的后置,最后执行
TraceFilter的后置逻辑——这里会清除当前线程的trace上下文(包括BaggageField) - 最后执行你的过滤器的后置逻辑(也就是打印id的代码),此时上下文已经被清空,自然拿不到值
而去掉@Order(Ordered.HIGHEST_PRECEDENCE)后,你的过滤器优先级低于TraceFilter,执行顺序变成:
TraceFilter先初始化trace上下文- 你的过滤器执行前置逻辑
- 调用
filterChain.doFilter执行业务逻辑设置id - 你的过滤器先执行后置逻辑(此时上下文还在,能正常拿到
id) - 最后
TraceFilter执行后置逻辑清除上下文
Spring(Brave)何时清除trace上下文?
准确来说是Brave的TraceFilter负责清除上下文:它会在**请求处理完成(即filterChain.doFilter执行完毕,准备返回响应)**时,在finally块中调用Tracer.clear()方法,清空当前线程的trace上下文(包括所有BaggageField数据),确保无论请求成功或失败都会执行清除操作。
如何让过滤器在Baggage上下文被清除前执行?
核心是让你的过滤器的**后置逻辑(filterChain之后的代码)**在TraceFilter的清除操作之前执行,有两种可行方式:
- 直接去掉
@Order(Ordered.HIGHEST_PRECEDENCE)注解,使用默认优先级即可(此时你的过滤器优先级低于TraceFilter,后置逻辑会先于清除操作执行) - 显式设置你的过滤器的
@Order值大于BraveTraceFilter的默认Order值(Order值越小优先级越高,更大的Order意味着更低的优先级)。在brave 5.14.1中,TraceFilter的默认Order是100,所以你可以设置@Order(101),确保你的过滤器后置逻辑在清除前执行。
修正后的代码示例:
@Component // 要么去掉Order注解,要么设置大于100的Order值 @Order(101) public class CollectionFilter extends OncePerRequestFilter { @Override protected void doFilterInternal( @NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException { if (!request.isAsyncStarted()) { try { filterChain.doFilter(request, response); // 此时上下文尚未被清除,能正常拿到id var id = BaggageField.getByName("id"); System.out.println(id); } catch (Exception e) { throw e; } } } }
内容的提问来源于stack exchange,提问作者tuk
相关产品推荐
相关产品推荐

