自定義過濾器和攔截器實現ThreadLocal線程封閉
攜手創作,共同成長!這是我參與「掘金日新計劃 · 8 月更文挑戰」的第10天,點擊查看活動詳情
線程封閉
線程封閉一般通過以下三個方法:
- Ad-hoc線程封閉:程序控制實現,最糟糕,忽略
- 堆棧封閉:局部變量,無併發問題
- 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();
}
} ```
請求訪問驗證
訪問調用接口,控制枱輸出如下:
本文內容到此結束了,
如有收穫歡迎點贊👍收藏💖關注✔️,您的鼓勵是我最大的動力。
如有錯誤❌疑問💬歡迎各位大佬指出。
保持熱愛,奔赴下一場山海。🏃🏃🏃
「其他文章」
- SpringCloud系列之服務治理Eureka
- 自定義過濾器和攔截器實現ThreadLocal線程封閉
- AQS同步組件-CyclicBarrier(循環屏障)解析和用例
- SpringBoot中的配置文件詳解(yml、properties全局配置和自定義配置、有趣的banner圖配置)
- 雲原生應用的概念和雲原生應用的 15 個特徵
- AQS同步組件-CountDownLatch解析和案例
- MyBatis從入門到精通—MyBatis插件原理探究和自定義插件實現
- 面試官:可以談談樂觀鎖和悲觀鎖嗎
- Spring JdbcTemplate&聲明式事務
- Java中的JDBC詳解
- Spring從入門到精通(一)—Spring概述、Spring的優勢和體系結構
- 數據庫連接池入門(c3p0、Druid)
- group by和having的區別
- Java流處理之序列化和打印流
- Cookie和Session詳解