线程封闭一般通过以下三个方法:
1.Ad-hoc线程封闭:程序控制实现,最糟糕,忽略
2.堆栈封闭:局部变量,无并发问题
3.ThreadLocal线程封闭:特别好的封闭方法
方法2是最常用的,变量定义在接口内,本文主要讲解方法三。
本例程是基于SpringBoot框架,并使用两个拦截器,分别为Filter和HandlerInterceptorAdapter
第一步,先定义拦截器继承Filter接口,实现ThredLocal.add()方法
第二步,在Application类实现Filter接口拦截/threadLocal/*的URL
第三步,封装ThredLocal的方法
第四步,实现另外个更细粒度的拦截器,HandlerInterceptorAdapter,调用ThredLocal.remove()方法
第五步,定义调用接口
第一步,先定义拦截器,比如拦截特定的URL
/* *Created by William on 2018/4/30 0030 * 拦截器 */ @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() { } }
第二步,在Application类实现Filter接口拦截/threadLocal/*的URL
/* *Created by William on 2018/4/26 0026 */ @SpringBootApplication public class ConcurrencyApplication extends WebMvcConfigurerAdapter { public static void main(String[] args) { SpringApplication.run(ConcurrencyApplication.class, args); } /** * 添加过滤器 * @return */ @Bean public FilterRegistrationBean httpFilter(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(new HttpFilter()); filterRegistrationBean.addUrlPatterns("/threadLocal/*"); return filterRegistrationBean; } /** * 请求前拦截处理 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HttpInterceptor()).addPathPatterns("/**"); } }
第三步,封装ThredLocal的方法
public class RequestHolder { private final static ThreadLocal<Long> requestHolder = new ThreadLocal<>(); public static void add(Long id) { requestHolder.set(id); } public static Long getId() { return requestHolder.get(); } public static void remove() { requestHolder.remove(); } }
第四步,实现另外个更细粒度的拦截器,HandlerInterceptorAdapter
HandlerInterceptorAdapter的介绍:http://www.cnblogs.com/EasonJim/p/7704740.html,相当于一个Filter拦截器,但是这个颗粒度更细,能使用Spring的@Autowired注入,代码如下,对threadLocal进行remove
/* *Created by William on 2018/4/30 0030 */ @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 @RequestMapping("/threadLocal") public class ThreadLocalController { @RequestMapping("/test") @ResponseBody public Long test() { return RequestHolder.getId(); } }
直接从RequestHolder获取之前存储的信息,结果如下:
2018-04-30 19:15:34.573 INFO 6648 --- [nio-8080-exec-8] concurrency.HttpFilter : do filter, 46, /threadLocal/test 2018-04-30 19:15:34.574 INFO 6648 --- [nio-8080-exec-8] concurrency.HttpInterceptor : preHandle 2018-04-30 19:15:34.577 INFO 6648 --- [nio-8080-exec-8] concurrency.HttpInterceptor : afterCompletion