前言:
- 应用场景:每次Http或者Grpc请求,想要进行一次存储在处处使用,且次次请求数据隔离。
- Http-ThreadLocal:让每个线程拥有自己的变量副本,从而实现线程隔离。
- Grpc-Context:可以在RPC调用之间传递上下文信息。
- 本文举例简单使用例子,及记录ThreadLocal的发生的隔离问题。
Java ThreadLocal使用示例:
-
定义一个
ThreadLocalUtil工具类来存储用户信息public class ThreadLocalUtil { private static final ThreadLocal<UserEntity> threadLocal = new ThreadLocal<>(); public static void setThreadLocal(UserEntity userEntity) { threadLocal.set(userEntity); } public static UserEntity getThreadLocal() { return threadLocal.get(); } public static void removeThreadLocal() { threadLocal.remove(); } } -
拦截器赋值
ThreadLocal的User用户信息@Slf4j @Configuration public class HelperInterceptor extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { UserEntity userEntity = new UserEntity(); try { String token = request.getHeader("TOKEN"); if (token != null && !token.isEmpty()) { String userName = JwtUtil.getUserName(token); String userId = JwtUtil.getUserId(token); userEntity.setUserName(userName); userEntity.setUserId(userId); } } catch (Exception e) { log.error("HelperInterceptor: ", e); } finally { ThreadLocalUtil.setThreadLocal(userEntity); filterChain.doFilter(request, response); } } } -
其他位置从ThreadLocal获取User信息
ThreadLocalUtil.getThreadLocal(); -
注意点:Java Spring Boot中,当使用内置的Web服务器如tomcat,线程池通常会被配置为可复用的并不会立即销毁,ThreadLocal又是与线程绑定的,一旦遇到使用过的线程可能会从ThreadLocal获取到旧数据,所以我们每次用完ThreadLocal就需要clear,或者每次ThreadLocal进行初始化赋值。
Grpc Context使用示例:
-
定义一个
GrpcMetadataKey工具类来存储Context Key,保证存取引用地址一致public interface GrpcMetadataKey { Context.Key<String> CONTEXT_IP = Context.key("ip"); } -
拦截器赋值Context CONTEXT_IP
的ip信息@GrpcGlobalServerInterceptor public class GlobalInterceptor implements ServerInterceptor { @Override public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) { Context context = Context.current().withValue( GrpcMetadataKey.CONTEXT_IP , headers.get(Metadata.Key.of("x-forwarded-for", Metadata.ASCII_STRING_MARSHALLER))); return Contexts.interceptCall(context, call, headers, next); } } -
其他位置从Context获取User信息
GrpcMetadataKey.CONTEXT_IP.get(); -
注意点:与Java ThreadLocal类似,Context一定要进行初始化赋值或清空。
717

被折叠的 条评论
为什么被折叠?



