在Spring Boot中使用ThreadLocal和嵌入式Tomcat来保存每个请求的数据是否安全?



我使用Spring Boot 2.7.0与嵌入式Tomcat。对于每个请求的用户上下文,我使用以下方法:

  1. 我有UserContext POJO
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class UserContext {
private Long userId = null;
private String userEmail = "";
}
  1. 我有UserContextHolder类用于在ThreadLocal实例中保存UserContext
import org.springframework.util.Assert;
public class UserContextHolder {
private static final ThreadLocal<UserContext> userContext = new ThreadLocal<>();
public static UserContext getContext() {
UserContext context = userContext.get();
if (context == null) {
context = createEmptyContext();
userContext.set(context);
}
return userContext.get();
}
public static void setContext(UserContext context) {
Assert.notNull(context, "Only non-null UserContext instances are permitted");
userContext.set(context);
}
public static UserContext createEmptyContext(){
return new UserContext();
}
}
  1. 和我有UserContextFilter设置数据从请求头到UserContext在当前线程:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Component
public class UserContextFilter implements Filter {
@Value("${user-id-header-name}")
private String userIdHeaderName;
@Value("${user-email-header-name}")
private String userEmailHeaderName;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String userIdFromHeaders = httpServletRequest.getHeader(userIdHeaderName);
String userEmailFromHeaders = httpServletRequest.getHeader(userEmailHeaderName);
UserContextHolder.getContext().setUserId(userIdFromHeaders == null ? null : Long.valueOf(userIdFromHeaders));
UserContextHolder.getContext().setUserEmail(userEmailFromHeaders);
filterChain.doFilter(httpServletRequest, servletResponse);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void destroy() {}
}

问题是:我可以使用这种方法来确保每个请求将被映射到它自己的线程,只有一个请求将被处理在同一时间在特定的线程?我担心我可以得到的情况下,一个线程将用于处理2个或更多的请求(但UserContext将是相同的)。

这种方法会导致记忆问题吗?

非常感谢你的回答:)

并且在特定线程中同时只处理一个请求?

At same time -是的,同一个线程内的执行是顺序的,所以它不会同时处理多个请求。但是,由于请求处理线程被池化和重用,因此它将被重用用于不同用户的未来请求。在请求处理后,您似乎没有从线程中清除上下文,因此这可能是问题所在。

执行清理的好地方是在调用filterChain.doFilter()之后。

最新更新