Home  >  Article  >  Java  >  How SpringBoot implements asynchronous calls elegantly

How SpringBoot implements asynchronous calls elegantly

WBOY
WBOYforward
2023-05-12 22:04:041711browse

Preface

  • Synchronous programming: In synchronous programming, tasks are executed one at a time. Only when one task is completed, the next task will be unblocked .

  • Asynchronous programming: In asynchronous programming, multiple tasks can be performed simultaneously. You can move to another task before the previous task is completed.

How SpringBoot implements asynchronous calls elegantly

In Spring Boot, we can use the @Async annotation to implement asynchronous behavior.

Implementation steps

1. Define an asynchronous service interfaceAsyncService.java

public interface AsyncService {

    void asyncMethod() throws InterruptedException;

    Future<String> futureMethod() throws InterruptedException;
}

2. Implement the defined interfaceAsyncServiceImpl.java

@Service
@Slf4j
public class AsyncServiceImpl implements AsyncService  {

    @Async
    @Override
    public void asyncMethod() throws InterruptedException {
        Thread.sleep(3000);
        log.info("Thread: [{}], Calling other service..", Thread.currentThread().getName());
    }

    @Async
    @Override
    public Future<String> futureMethod() throws InterruptedException {
        Thread.sleep(5000);
        log.info("Thread: [{}], Calling other service..", Thread.currentThread().getName());
        return new AsyncResult<>("task Done");
    }
}
  • AsyncServiceImpl is a spring managed bean.

  • Your asynchronous method must be public and decorated with the @Async annotation.

  • The return type is restricted to void or Future.

3. Define a controllerAsyncController.java

@EnableAsync
@RestController
@Slf4j
public class AsyncController {
    @Autowired
    AsyncService asyncService;

    @GetMapping("/async")
    public String asyncCallerMethod() throws InterruptedException {
        long start = System.currentTimeMillis();
        log.info("call async method, thread name: [{}]", Thread.currentThread().getName());
        asyncService.asyncMethod();
        String response = "task completes in :" +
                (System.currentTimeMillis() - start) + "milliseconds";
        return response;
    }

    @GetMapping("/asyncFuture")
    public String asyncFuture() throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();
        log.info("call async method, thread name: [{}]", Thread.currentThread().getName());
        Future<String> future = asyncService.futureMethod();
        // 阻塞获取结果
        String taskResult = future.get();
        String response = taskResult + "task completes in :" +
                (System.currentTimeMillis() - start) + "milliseconds";
        return response;
    }
}
  • Key point, you need to add annotations to enable asynchronous@EnableAsync , of course, this annotation can be added elsewhere.

  • When this interface is called externally, asyncMethod() will be executed by another thread created by the default task executor, and the main thread does not need to wait for the completion of the asynchronous method execution.

4. Run it

Now let’s run it and see if it returns asynchronously.

How SpringBoot implements asynchronous calls elegantly

How SpringBoot implements asynchronous calls elegantly

You can see that the /async interface is called, and the method is called in the final step.

How SpringBoot implements asynchronous calls elegantly

How SpringBoot implements asynchronous calls elegantly

Call /asyncFuture and find that the return is more than 5 seconds. Isn’t it asynchronous? In fact, it is also asynchronous, as you can see from the logs, but what we return is Future, and calling Futrue.get() is blocked.

Customized asynchronous task executor and exception handling

Now let’s see what happens if an error is reported in the exception method? Modify the asynchronous code as follows, and a runtime exception will be thrown:

How SpringBoot implements asynchronous calls elegantly

#Execute the asynchronous interface again, as shown below, and the default thread pool and exception handling will be used.

How SpringBoot implements asynchronous calls elegantly

We can also customize the asynchronous method's exception handling and asynchronous task executor. We need to configure AsyncUncaughtExceptionHandler, as shown in the following code:

@Configuration
public class AsynConfiguration extends AsyncConfigurerSupport {
   @Override
   public Executor getAsyncExecutor() {
      ThreadPoolTaskExecutor executor = new 
                ThreadPoolTaskExecutor();
      executor.setCorePoolSize(3);
      executor.setMaxPoolSize(4);
      executor.setThreadNamePrefix("asyn-task-thread-");
      executor.setWaitForTasksToCompleteOnShutdown(true);
      executor.initialize();
      return executor;
  }
  @Override
  public AsyncUncaughtExceptionHandler  
         getAsyncUncaughtExceptionHandler() {
     return new AsyncUncaughtExceptionHandler() {
   
        @Override
        public void handleUncaughtException(Throwable ex, 
           Method method, Object... params) {
           System.out.println("Exception: " + ex.getMessage());
           System.out.println("Method Name: " + method.getName());
           ex.printStackTrace();
        }
    };
  }
}

Run again, the results are as follows:

How SpringBoot implements asynchronous calls elegantly

How @Async works

must be done by using the @EnableAsync annotation Annotate the main application class or any direct or indirect asynchronous method caller class to enable async support. Mainly implemented through proxy mode, the default mode is Proxy, the other is AspectJ. Proxy mode only allows calls to be intercepted through a proxy. Never call an async method from the same class in which it is defined, it won't work.

When annotating a method with @Async, it will create a proxy for the object based on the "proxyTargetClass" attribute. When spring executes this method, by default it searches for the associated thread pool definition. The only spring framework TaskExecutor bean or Executor bean named "taskExecutor" in the context. If neither of these is resolvable, the spring framework SimpleAsyncTaskExecutor will be used by default to handle the execution of asynchronous methods.

The above is the detailed content of How SpringBoot implements asynchronous calls elegantly. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete