自定義過濾器和攔截器實現ThreadLocal線程封閉

語言: CN / TW / HK

攜手創作,共同成長!這是我參與「掘金日新計劃 · 8 月更文挑戰」的第10天,點擊查看活動詳情

線程封閉

線程封閉一般通過以下三個方法:

  1. Ad-hoc線程封閉:程序控制實現,最糟糕,忽略
  2. 堆棧封閉:局部變量,無併發問題
  3. ThreadLocal線程封閉:特別好的封閉方法

方法2是最常用的,變量定義在接口內,本文主要講解方法三,SpringBoot項目通過自定義過濾器和攔截器實現ThreadLocal線程封閉。實現Filter接口自定義過濾器和繼承HandlerInterceptorAdapter自定義攔截器。

ThreadLocal線程封閉實現步驟

封裝ThredLocal的方法

```java /* *

自定義RequestHolder

* * @Author zjq * @Date 2021/12 / public class RequestHolder {

private final static ThreadLocal<Long> requestHolder = new ThreadLocal<>();

public static void set(Long id) {
    requestHolder.set(id);
}

public static Long get() {
    return requestHolder.get();
}

public static void remove() {
    requestHolder.remove();
}

} ```

自定義過濾器

自定義定義攔截器繼承Filter接口,實現ThredLocal.add()方法 ```java /* *

自定義過濾器

* * @Author zjq * @Date 2021/12/7 / @Slf4j public class HttpFilter implements Filter {

/**
 * 為Filter初始化 提供支持
 *
 * @param filterConfig
 * @throws ServletException
 */
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

/**
 * 攔截到要執行的請求時,doFilter就會執行。這裏我們可以寫對請求和響應的預處理。
 * FilterChain把請求和響應傳遞給下一個 Filter處理
 *
 * @param servletRequest
 * @param servletResponse
 * @param filterChain
 * @throws IOException
 * @throws ServletException
 */
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    //把普通servlet強轉成httpServlet
    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    Long threadId = Thread.currentThread().getId();
    log.info("do filter,threadId:{} servletPath:{}", threadId, httpServletRequest.getServletPath());
    //把當前線程id放入requestHolder
    RequestHolder.set(threadId);
    //放行
    filterChain.doFilter(httpServletRequest, servletResponse);
}

/**
 * Filter 實例銷燬前的準備工作
 */
@Override
public void destroy() {

}

} ```

自定義攔截器

自定義攔截器在線程使用完畢後移除ThredLocal中內容,避免內存溢出 ```java /* *

自定義攔截器

* * @Author zjq * @Date 2021/12/7 / @Slf4j public class HttpInterceptor extends HandlerInterceptorAdapter {

/**
 * 攔截處理程序的執行。在 HandlerMapping 確定合適的處理程序對象之後,在 HandlerAdapter 調用處理程序之前調用。
 * @param request
 * @param response
 * @param handler
 * @return
 * @throws Exception
 */
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    log.info("preHandle執行。。。");
    return true;
}

/**
 * 請求處理完成後(渲染視圖後)的回調。將在處理程序執行的任何結果上調用,從而允許進行適當的資源清理。
 * @param request
 * @param response
 * @param handler
 * @param ex
 * @throws Exception
 */
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    RequestHolder.remove();
    log.info("afterCompletion執行。。。");
    return;
}

} ```

Application類啟動類中配置自定義過濾器和攔截器

```java /* * * @author zjq / @SpringBootApplication public class Application extends WebMvcConfigurationSupport {

public static void main(String[] args) {
    SpringApplication.run(ConcurrencyApplication.class, args);
}

/**
 * 自定義過濾器
 * @return
 */
@Bean
public FilterRegistrationBean filterRegistrationBean(){
    FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
    filterRegistrationBean.setFilter(new HttpFilter());
    //設置自定義過濾器攔截的url
    filterRegistrationBean.addUrlPatterns("/threadLocal/*");
    return filterRegistrationBean;
}

/**
 * 定義自定義攔截器原先需要繼承WebMvcConfigurerAdapter
 * SpringBoot2.0後WebMvcConfigurerAdapter被定義成過時了,推薦使用繼承WebMvcConfigurationSupport
 * @param registry
 */
@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new HttpInterceptor()).addPathPatterns("/**");
}

} ```

定義調用接口

```java /* * ThreadLocal測試controller * @author zjq / @Controller @RequestMapping("/threadLocal") public class ThreadLocalController {

@RequestMapping("/test")
@ResponseBody
public Long test() {
    return RequestHolder.get();
}

} ```

請求訪問驗證

訪問調用接口,控制枱輸出如下: image.png

本文內容到此結束了,

如有收穫歡迎點贊👍收藏💖關注✔️,您的鼓勵是我最大的動力。

如有錯誤❌疑問💬歡迎各位大佬指出。

主頁共飲一杯無的博客彙總👨‍💻

保持熱愛,奔赴下一場山海。🏃🏃🏃

a37032f76d3ebe77e3e3d265ff1e1d7.jpg