在最近完成的课设中,发现通过ThreadLocal进行信息与线程的绑定可以方便之后的代码编写。部分出自参考 设计一个可扩展的用户登录系统(3) 。
以一个登录为例,我们需要将已完成登录的用户信息与其操作的线程进行绑定,而ThreadLocal能够很好地实现这个功能。
public class UserContext implements AutoCloseable {
static final ThreadLocal<User> current = new ThreadLocal<User>();
public UserContext(User user) {
current.set(user);
}
public static User getCurrentUser() {
return current.get();
}
public void close() {
current.remove();
}
}
我们将一个User类绑定到当前线程,并使用统一的filter进行操作:
public class MyFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
//根据cookie判断user,省略方法体
User user = tryGetAuthenticatedUser(request, response);
try (UserContext context = new UserContext(user)) {
chain.doFilter(request, response);
}
}
}
但是在测试过程中发现,只要有用户进行了登录验证就会有一些未进行登录验证的用户请求线程里自带了user信息。
原来是tomcat在启动后一开始收到请求,它就会创建一个基于本身配置minSapreThreads参数的线程池,之后的每次请求线程都是从这个线程池中取出工作线程,而不是创建一个新的线程。(线程池->取出工作线程->处理请求->将线程放回池中)
我们就需要在这个UserContext中创建方法解除绑定:
//清除TheadLocal信息
public static void destroy(){
current.remove();
}
接着同样可以在同一的filter中进行解绑操作。这样在之后的代码编写中我们就只需要通过这样的一句简单的代码获取到绑定到当前线程中的User信息:
UserContext.getCurrentUser();
每天进步一点点!