ThreadLocal工具类
- 线程通过该工具类,将线程私有的数据存入ThreadLocal中;
public class RequestHolder {
private final static ThreadLocal<Long> requestHolder = new ThreadLocal<>();
/**
* 将当前线程的ID存储到ThreadLocal中
* @param id
*/
public static void add(Long id) {
requestHolder.set(id);
}
public static Long getId() {
return requestHolder.get();
}
/**
* 在请求处理完成后,从ThreadLocal中将本次请求的相关信息清除,
* 以免造成内存泄漏;
*/
public static void remove() {
requestHolder.remove();
}
}
过滤器
- 在请求到达Controller前,将线程id存入ThreadLocal中;
import com.example.concurrency.example.threadlocal.RequestHolder;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Slf4j
public class HttpFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
log.info("do filter, {}, {}", Thread.currentThread().getId(), request.getServletPath());
RequestHolder.add(Thread.currentThread().getId());
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {}
}
拦截器
- 在请求处理完成后,将当前线程的线程id从ThreadLocal中删除,避免内存泄漏;
import com.example.concurrency.example.threadlocal.RequestHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class HttpInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("preHandle");
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
RequestHolder.remove();
log.info("afterCompletion");
return;
}
}
Controller
- 处理请求,在处理的时候可以从ThreadLocal中把线程id取出来;
@Controller
@RequestMapping("/threadLocal")
public class ThreadLocalController {
@RequestMapping("/test")
@ResponseBody
public Long test() {
return RequestHolder.getId();
}
}
Springboot启动类
- 在启动类中注册过滤器和拦截器;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@SpringBootApplication
public class ConcurrencyApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(ConcurrencyApplication.class, args);
}
@Bean
public FilterRegistrationBean httpFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new HttpFilter());
registrationBean.addUrlPatterns("/threadLocal/*");
return registrationBean;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HttpInterceptor()).addPathPatterns("/**");
}
}
发送请求
{{host}}/threadLocal/test
响应:
2019-03-28 16:49:32.659 INFO 2432 --- [nio-8080-exec-1] com.example.concurrency.HttpFilter : do filter, 31, /threadLocal/test
2019-03-28 16:49:32.670 INFO 2432 --- [nio-8080-exec-1] com.example.concurrency.HttpInterceptor : preHandle
2019-03-28 16:49:32.742 INFO 2432 --- [nio-8080-exec-1] com.example.concurrency.HttpInterceptor : afterCompletion