SpringBoot中使用@Async注解失效場景及說明
場景一:調(diào)用者與被調(diào)用者在同一個類中
當(dāng)調(diào)用 @Async 注解的方法的類和被調(diào)用的方法在同一個類中時,@Async 注解不會生效。因?yàn)?Spring 的 AOP 代理是基于接口的,對于同一個類中的方法調(diào)用,不會經(jīng)過代理,因此 @Async 注解不會被處理。
例如:
@Service
public class MyService {
@Async
public void asyncMethod() {
// 模擬耗時操作
try {
System.out.println("開始異步執(zhí)行");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Async method executed.");
}
public void callAsyncMethod() {
asyncMethod(); // 直接調(diào)用,不會異步執(zhí)行
}
}場景二:配置類未啟用異步支持
如果配置類中沒有啟用異步支持,即沒有使用 @EnableAsync 注解,那么 @Async 注解同樣不會生效。
例如:
// 沒有使用 @EnableAsync 注解,因此不會啟用異步支持
@Configuration
public class AsyncConfig {
// ... 其他配置 ...
}
@Service
public class MyService {
@Async
public void asyncMethod() {
// 模擬耗時操作
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Async method executed.");
}
}場景三:方法不是 public 的
@Async 注解的方法必須是 public 的,否則不會被 Spring AOP 代理捕獲,導(dǎo)致異步執(zhí)行不生效。
例如:
@Service
public class MyService {
@Async // 但這個方法不是 public 的,所以 @Async 不會生效
protected void asyncMethod() {
// 模擬耗時操作
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Async method executed.");
}
public void callAsyncMethod() {
asyncMethod(); // 直接調(diào)用,但由于 asyncMethod 不是 public 的,因此不會異步執(zhí)行
}
}場景四:線程池未正確配置
在使用 @Async 注解時,如果沒有正確配置線程池,可能會遇到異步任務(wù)沒有按預(yù)期執(zhí)行的情況。例如,線程池被配置為只有一個線程,且該線程一直被占用,那么新的異步任務(wù)就無法執(zhí)行。
例如:
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
// 創(chuàng)建一個只有一個線程的線程池,這會導(dǎo)致并發(fā)問題
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(1);
executor.setQueueCapacity(10);
executor.setThreadNamePrefix("Async-");
executor.initialize();
return executor;
}
// ... 其他配置 ...
}
@Service
public class MyService {
@Async
public void asyncMethod() {
// 模擬耗時操作
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Async method executed.");
}
}場景五:異常處理不當(dāng)
如果在異步方法中拋出了異常,并且沒有妥善處理,那么這個異??赡軙?dǎo)致任務(wù)失敗,而調(diào)用者可能無法感知到異常的發(fā)生。
例如:
@Service
public class MyService {
@Async
public void asyncMethod() {
// 模擬一個可能會拋出異常的耗時操作
throw new RuntimeException("Async method exception");
}
}
// 調(diào)用者
@Service
public class CallerService {
@Autowired
private MyService myService;
public void callAsyncMethod() {
myService.asyncMethod(); // 調(diào)用異步方法,但如果該方法拋出異常,調(diào)用者不會立即感知到
}
}場景六:Spring代理未生效
如果通過 new 關(guān)鍵字直接創(chuàng)建了服務(wù)類的實(shí)例,而不是通過 Spring 容器來獲取,那么 Spring 的 AOP 代理將不會生效,導(dǎo)致 @Async 注解無效。
例如:
@Service
public class MyService {
@Async
public void asyncMethod() {
// 模擬耗時操作
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Async method executed.");
}
}
public class SomeNonSpringClass {
public void someMethod() {
MyService myService = new MyService(); // 直接通過 new 創(chuàng)建 MyService 實(shí)例,不會經(jīng)過 Spring 代理
myService.asyncMethod(); // 這里 @Async 不會生效
}
}場景七:使用 @Transactional 與 @Async 同時注解方法,導(dǎo)致事務(wù)失效
在同一個方法上同時使用 @Transactional 和 @Async 注解可能會導(dǎo)致問題。由于 @Async 會導(dǎo)致方法在一個新的線程中執(zhí)行,而 @Transactional 通常需要在一個由 Spring 管理的事務(wù)代理中執(zhí)行,這兩個注解的結(jié)合使用可能會導(dǎo)致事務(wù)管理失效或行為不可預(yù)測。此種場景不會導(dǎo)致@Async注解失效,但是會導(dǎo)致@Transactional注解失效,也就是事務(wù)失效。
例如:
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
// 錯誤的用法:同時使用了 @Transactional 和 @Async
@Transactional
@Async
public void asyncTransactionalMethod() {
// 模擬一個數(shù)據(jù)庫操作
myRepository.save(new MyEntity());
// 模擬可能拋出異常的代碼
if (true) {
throw new RuntimeException("Database operation failed!");
}
}
}
@Repository
public interface MyRepository extends JpaRepository<MyEntity, Long> {
// ...
}
@Entity
public class MyEntity {
// ... 實(shí)體類的屬性和映射 ...
}總結(jié)一下 :
絕大多數(shù)人會遇到的坑點(diǎn)主要會集中在沒有配置自定義線程池、異步方法在同一個類中調(diào)用、事務(wù)不起作用這幾個問題上。所以,萬金油的寫法還是專門定義一個AsyncService,將異步方法都寫在里面,需要使用的時候,就在其他類將其注入即可。
以上就是SpringBoot中使用@Async注解失效場景及說明的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot @Async注解失效的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
ThreadLocal內(nèi)存泄露的產(chǎn)生原因和處理方法
ThreadLocal 的內(nèi)存泄漏問題通常發(fā)生在使用 ThreadLocal 存儲對象時,尤其是在多線程環(huán)境中,線程池中的線程復(fù)用可能導(dǎo)致一些資源沒有及時清理,從而引發(fā)內(nèi)存泄漏,所以本文給大家介紹了ThreadLocal內(nèi)存泄露的產(chǎn)生原因和處理方法,需要的朋友可以參考下2024-12-12
SpringBoot @Cacheable自定義KeyGenerator方式
這篇文章主要介紹了SpringBoot @Cacheable自定義KeyGenerator方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
Java API方式調(diào)用Kafka各種協(xié)議的方法
本篇文章主要介紹了Java API方式調(diào)用Kafka各種協(xié)議的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09
Java實(shí)現(xiàn)將word轉(zhuǎn)換為html的方法示例【doc與docx格式】
這篇文章主要介紹了Java實(shí)現(xiàn)將word轉(zhuǎn)換為html的方法,結(jié)合實(shí)例形式分析了java針對doc與docx格式文件的相關(guān)轉(zhuǎn)換操作技巧,需要的朋友可以參考下2019-03-03
詳細(xì)聊聊Spring MVC重定向與轉(zhuǎn)發(fā)
大家應(yīng)該都知道請求重定向和請求轉(zhuǎn)發(fā)都是web開發(fā)中資源跳轉(zhuǎn)的方式,這篇文章主要給大家介紹了關(guān)于Spring MVC重定向與轉(zhuǎn)發(fā)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09
Java高效實(shí)現(xiàn)電商產(chǎn)品排序?qū)崙?zhàn)
這篇文章主要為大家介紹了Java高效實(shí)現(xiàn)電商產(chǎn)品排序?qū)崙?zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11

