解決Springboot中@Async注解獲取不到上下文信息問題
問題描述
springboot項目中,需要使用到異步調(diào)用某個方法,此時 第一個想到的就是 @Async 注解,但是 發(fā)現(xiàn) 方法執(zhí)行報錯了,具體報錯如下:
java.lang.NullPointerException
at com.ruoyi.common.utils.ServletUtils.getRequest(ServletUtils.java:56)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:782)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:717)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:443)
at com.ruoyi.web.ecs.service.impl.EcsCollectOperateServiceImpl.collect(EcsCollectOperateServiceImpl.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:90)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115)
at java.util.concurrent.FutureTask.run(FutureTask.java:277)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1160)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.lang.Thread.run(Thread.java:825)
上面日志有點多,其實核心就是這一部分日志:
java.lang.NullPointerException
at com.ruoyi.common.utils.ServletUtils.getRequest(ServletUtils.java:56)
這塊邏輯就是,使用spring底層提供的獲取上下文信息的方法。
所以說明 獲取不到上下文信息,結(jié)果導(dǎo)致報錯
解決辦法
- 對自定義的配置類 進(jìn)行改造,原來的配置類是這樣的:
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
public class AsyncConfiguration {
private static final Logger logger = LoggerFactory.getLogger(AsyncConfiguration.class);
@Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// 核心線程數(shù):線程池創(chuàng)建時候初始化的線程數(shù)
taskExecutor.setCorePoolSize(10);
// 最大線程數(shù):線程池最大的線程數(shù),只有在緩沖隊列滿了之后才會申請超過核心線程數(shù)的線程
taskExecutor.setMaxPoolSize(20);
// 緩沖隊列:用來緩沖執(zhí)行任務(wù)的隊列
taskExecutor.setQueueCapacity(50);
// 允許線程的空閑時間60秒:當(dāng)超過了核心線程之外的線程在空閑時間到達(dá)之后會被銷毀
taskExecutor.setKeepAliveSeconds(60);
// 線程池名的前綴:設(shè)置好了之后可以方便我們定位處理任務(wù)所在的線程池
taskExecutor.setThreadNamePrefix("HiTask-");
// 緩沖隊列滿了之后的拒絕策略:由調(diào)用線程處理(一般是主線程)
//taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
taskExecutor.initialize();
return taskExecutor;
}
class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
logger.error("MethodName={},Throwable={}",method.getName(),throwable.toString());
}
}
}- 改造之后:
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
@Configuration
@EnableAsync
public class AsyncConfiguration {
private static final Logger logger = LoggerFactory.getLogger(AsyncConfiguration.class);
@Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// 核心線程數(shù):線程池創(chuàng)建時候初始化的線程數(shù)
taskExecutor.setCorePoolSize(10);
// 最大線程數(shù):線程池最大的線程數(shù),只有在緩沖隊列滿了之后才會申請超過核心線程數(shù)的線程
taskExecutor.setMaxPoolSize(20);
// 緩沖隊列:用來緩沖執(zhí)行任務(wù)的隊列
taskExecutor.setQueueCapacity(50);
// 允許線程的空閑時間60秒:當(dāng)超過了核心線程之外的線程在空閑時間到達(dá)之后會被銷毀
taskExecutor.setKeepAliveSeconds(60);
// 線程池名的前綴:設(shè)置好了之后可以方便我們定位處理任務(wù)所在的線程池
taskExecutor.setThreadNamePrefix("HiTask-");
// 緩沖隊列滿了之后的拒絕策略:由調(diào)用線程處理(一般是主線程)
//taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
taskExecutor.initialize();
//解決使用@Async注解,獲取不到上下文信息的問題
taskExecutor.setTaskDecorator(runnable -> {
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
return ()->{
try {
// 我們set 進(jìn)去 ,其實是一個ThreadLocal維護(hù)的.
RequestContextHolder.setRequestAttributes(requestAttributes);
runnable.run();
} finally {
// 最后記得釋放內(nèi)存
RequestContextHolder.resetRequestAttributes();
}
};
});
return taskExecutor;
}
class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
logger.error("MethodName={},Throwable={}",method.getName(),throwable.toString());
}
}
}總結(jié)
解決使用@Async注解,獲取不到上下文信息的問題,只需要增加這一段代碼即可
taskExecutor.setTaskDecorator(runnable -> {
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
return ()->{
try {
// 我們set 進(jìn)去 ,其實是一個ThreadLocal維護(hù)的.
RequestContextHolder.setRequestAttributes(requestAttributes);
runnable.run();
} finally {
// 最后記得釋放內(nèi)存
RequestContextHolder.resetRequestAttributes();
}
};
});
額外補(bǔ)充一點
如果使用 @Async注解,發(fā)現(xiàn)沒有生效,那有可能 你沒有加 @EnableAsync 注解。
@EnableAsync注解表示 開啟異步任務(wù),可以寫在springboot的啟動類上,也可以寫在 配置類上
到此這篇關(guān)于解決Springboot中@Async注解獲取不到上下文信息問題的文章就介紹到這了,更多相關(guān)Springboot @Async獲取上下文內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java設(shè)計模式以虹貓藍(lán)兔的故事講解代理模式
代理模式是Java常見的設(shè)計模式之一。所謂代理模式是指客戶端并不直接調(diào)用實際的對象,而是通過調(diào)用代理,來間接的調(diào)用實際的對象2022-04-04
關(guān)于swagger配置及踩坑@Api參數(shù)postion無效解決接口排序問題
這篇文章主要介紹了關(guān)于swagger配置及踩坑@Api參數(shù)postion無效解決接口排序問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06

