Spring Boot:异步方法未在单独的线程中运行

Kew*_*hka 5 asynchronous spring-boot

我想在单独的线程中运行一个方法。因此我尝试使用@Async但它不起作用。打印输出始终引用相同的线程 ID。

我的应用程序.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;
    }

}
Run Code Online (Sandbox Code Playgroud)

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());
}
}
Run Code Online (Sandbox Code Playgroud)

Kav*_*lai 6

  • @TransactionalSpring通过创建代理来达到预期的效果 @Async。因此,当您注入时MyService,您实际上是在注入一个MyService包装原始类实例的代理。因此,如果调用通过此代理,那么这些注释将起作用,而如果在没有代理的情况下直接调用该方法,则它将不起作用。

  • ProxyMyService.handle() --> MyService.handle() --> MyService.handleAsync() 就你而言,当你想要的时候它就会这样发生ProxyMyService.handle() --> MyService.handle() --> ProxyMyService. handleAsync() -->MyService.handleAsync()

  • 为了实现这一目标,您应该创建两个服务类,并将一个方法放在类中,将第二种方法放在另一个类中

笔记

而且,当您在两个不同的服务中执行此操作时,即使handleAsync将以事务方式执行,它也不会使用 handleAsync 方法内的事务。由于事务要在该方法内传播,因此它们应该在同一线程上执行


Ana*_*han 5

第一件事:@Async 如果注释由 \xe2\x80\x98this\xe2\x80\x99 调用,则注释不起作用。来自官方文档

\n
\n

对该对象引用的方法调用将是对代理的调用,因此代理将能够委托给与该特定方法调用相关的所有拦截器(建议)。然而,一旦调用最终到达目标对象,在本例中是 SimplePojo 引用,它可能对自身进行的任何方法调用,例如 this.bar() 或 this.foo(),都将被\n针对 this 引用而不是代理调用

\n
\n

添加@Kavithakaran 提供的答案,您的代码的问题是您正在尝试使用@Async@Transactional。您有一个从同一类中的事务方法触发的异步方法。

\n

当使用@Async注释时,Spring 框架将在 Spring 代理上使用 AOP(面向方面​​编程),@Component将此方法的调用包装在 Runnable 中,并将此 Runnable 调度到任务执行器上。同样,@Transactional也使用AOP和代理。在通常没有异步的事务方法中,事务通过调用层次结构从一个 Spring 传播@Component到另一个 Spring。

\n

但是就像您的情况一样,当一个@Transactional方法调用一个方法时@Async,这种情况不会发生,因为异步方法是从同一个类调用的,它使用相同的线程。可能是因为 @Async注释如果由 \xe2\x80\x98this\xe2\x80\x99 调用则不起作用。@Async 的行为就像 @Transactional 注释。

\n

另外,为了使 Spring 管理方法的事务@Async,或者@Component方法本身应该声明注释@Transactional,这样即使方法正在异步执行,Spring 也会管理事务。所以,就像前面的答案一样,我的建议是将异步方法提取到单独的组件中,使其成为事务性的,并在该组件类方法上使用 aync 方法。有异步方法,例如:

\n
@Slf4j\n@Transactional\n@Component\npublic class AsyncClass {\n\n  @Async("threadPoolTaskExecutor")\n  public void handleAsync(Message message) {\n      System.out.println("Execute method asynchronously - " + \n      Thread.currentThread().getName());\n  }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n