[英]Spring Boot: Async method not running in separate Thread
我想在單獨的線程中運行一個方法。 因此我嘗試使用 @Async 但它不起作用。 打印的 output 始終引用相同的線程 ID。
MyApp.java
@SpringBootApplication
@EnableAsync
@EnableConfigurationProperties(ConfigProperties.class)
public class MyApp {
public static void main(String[] args) throws Exception {
SpringApplication.run(MyApp.class, args);
}
@Bean("threadPoolTaskExecutor")
public TaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(1000);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("Async-");
return executor;
}
}
MyService.java
@Slf4j
@Service
public class MyService implements ISichtServiceBroker {
@Inject
public MyService(Helper helper) {
this.helper = helper;
}
@Transactional
public void handle(Message message) {
System.out.println("Execute method synchronously - " + Thread.currentThread().getName());
handleAsync(message);
}
@Async("threadPoolTaskExecutor")
public void handleAsync(Message message) {
System.out.println("Execute method asynchronously - " + Thread.currentThread().getName());
}
}
Spring 通過創建代理實現@Transactional
和@Async
的預期效果。 因此,當您注入MyService
時,您實際上是在注入MyService
的代理,該代理包裝了您的原始 class 實例。 因此,如果通過此代理調用 go,那么這些注釋將起作用,如果在沒有代理的情況下直接調用該方法,它將不起作用。
在您的情況下,當您想要ProxyMyService.handle() --> MyService.handle() --> ProxyMyService. handleAsync() -->MyService.handleAsync()
ProxyMyService.handle() --> MyService.handle() --> MyService.handleAsync()
時,它就像這樣發生ProxyMyService.handle() --> MyService.handle() --> ProxyMyService. handleAsync() -->MyService.handleAsync()
ProxyMyService.handle() --> MyService.handle() --> ProxyMyService. handleAsync() -->MyService.handleAsync()
為了實現這一點,您應該創建兩個服務類並將一個方法放在 class 中,將第二種方法放在另一個中
筆記
而且,當您在兩個不同的服務中執行此操作時,即使handleAsync
將以事務方式執行,它也不會使用 handleAsync 方法中的事務。 因為事務要在該方法內部傳播,所以它們應該在同一個線程上執行
第一件事: @Async
注釋在被 'this' 調用時不起作用。 來自官方文檔:
對 object 引用的方法調用將是對代理的調用,因此代理將能夠委托與該特定方法調用相關的所有攔截器(建議)。 但是,一旦調用最終到達目標 object(在這種情況下為 SimplePojo 引用),它可能對自身進行的任何方法調用,例如 this.bar() 或 this.foo(),都將針對這個參考,而不是代理
除了@Kavithakaran 提供的答案之外,您的代碼問題是您正在嘗試使用@Async
和@Transactional
。 您有一個異步方法從同一個 class 中的事務方法觸發。
當使用@Async
注解時,Spring 框架將在@Component
的 Spring 代理上使用 AOP(面向方面編程),以將對此方法的調用包裝在 Runnable 中,並將此 Runnable 安排在任務執行器上。 同樣, @Transactional
也使用 AOP 和代理。 在通常沒有 Async 的 Transacional 方法中,事務通過調用層次結構從一個 Spring @Component
傳播到另一個。
但是就像你的情況一樣,當@Transactional
方法調用@Async
時,這不會發生,因為異步方法是從同一個class 調用的,它使用同一個線程。 可能是因為 @Async注釋在被 'this' 調用時不起作用。 @Async 的行為就像 @Transactional 注釋一樣。
此外,為了使 Spring 管理@Async
方法的事務, @Component
Component 或方法本身應聲明@Transactional
注釋,這樣 Spring 將管理事務,即使方法正在異步執行。所以,就像先前的回答我的建議是將異步方法提取到一個單獨的組件中,使其具有事務性,並在該組件 class 方法上使用 aync 方法。具有異步方法,例如:
@Slf4j
@Transactional
@Component
public class AsyncClass {
@Async("threadPoolTaskExecutor")
public void handleAsync(Message message) {
System.out.println("Execute method asynchronously - " +
Thread.currentThread().getName());
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.