您好,登錄后才能下訂單哦!
這篇文章給大家介紹SpringBoot 異步線程間傳遞上下文方式是怎樣的,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
SpringBoot項目中,經常使用@Async來開啟一個子線程來完成異步操作。主線程中的用戶信息需要傳遞給子線程
在啟動類里加上@EnableAsync注解
@EnableAsync @SpringBootApplication public class Application {}
新建一個配置類,實現AsyncConfigurer接口,并重寫getAsyncExecutor方法
@Configuration public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(50); executor.setThreadNamePrefix("async-pool-"); // 這一步是關鍵,異步Task裝飾器 executor.setTaskDecorator(new MyContextDecorator()); executor.initialize(); return executor; } }
新建一個異步任務裝飾器,實現TaskDecorator接口,并重寫decorate方法
public class MyContextDecorator implements TaskDecorator { @Override @Nonnull public Runnable decorate(@Nonnull Runnable runnable) { // 獲取主線程中的請求信息(我們的用戶信息也放在里面) RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); return () -> { try { // 將主線程的請求信息,設置到子線程中 RequestContextHolder.setRequestAttributes(attributes); // 執行子線程,這一步不要忘了 runnable.run(); } finally { // 線程結束,清空這些信息,否則可能造成內存泄漏 RequestContextHolder.resetRequestAttributes(); } }; }
補充下:RequestContextHolder內部是基于ThreadLocal實現的,因此在使用set get時,都是和當前線程綁定的。當然,使用者的用戶信息不一定放在了RequestContextHolder里面,讀者可以自行擴展。
到此,通過@Async開啟的子線程,就可以正常拿到父線程中的Request信息了。
項目中多線程添加數據,mybatisplus元數據填充功能,填充創建人時,數據是來自 spring security SecurityContextHolder.getContext.getAuthentication,同步操作時,能正常獲取,而異步執行時空指針異常。
配置安全上下文全局策略SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)
Spring Security 安全上下文默認策略為MODE_THREADLOCAL,ThreadLocal機制來保存每個使用者的安全上下文。
這意味著,只要針對某個使用者的邏輯執行都是在同一個線程中進行,即使不在各個方法之間以參數的形式傳遞其安全上下文,各個方法也能通過SecurityContextHolder工具獲取到該安全上下文。
只要在處理完當前使用者的請求之后注意清除ThreadLocal中的安全上下文,這種使用ThreadLocal的方式是很安全的。
MODE_GLOBAL
: JVM中所有的線程使用同一個安全上下文
MODE_INHERITABLETHREADLOCAL
:有些應用會有自己的線程創建,并且希望這些新建線程也能使用創建者的安全上下文。這種效果,可以通過將SecurityContextHolder配置成MODE_INHERITABLETHREADLOCAL策略達到。
在配置文件中添加:
@PostConstruct public void init(){ SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL); }
@PostConstruct注解好多人以為是Spring提供的。其實是Java自己的注解。
Java中該注解的說明:@PostConstruct該注解被用來修飾一個非靜態的void()方法。被@PostConstruct修飾的方法會在服務器加載Servlet的時候運行,并且只會被服務器執行一次。PostConstruct在構造函數之后執行,init()方法之前執行。
通常我們會是在Spring框架中使用到@PostConstruct注解 該注解的方法在整個Bean初始化中的執行順序:
Constructor(構造方法) -> @Autowired(依賴注入) -> @PostConstruct(注釋的方法)
關于SpringBoot 異步線程間傳遞上下文方式是怎樣的就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。