Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use @ Async asynchronous calls in Spring

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces how to use @ Async asynchronous call in Spring, which has a certain reference value. Interested friends can refer to it. I hope you will learn a lot after reading this article.

Introduction to calling method Async asynchronously using @ Async

Asynchronous method invocation usage scenarios: processing logs, sending emails, and text messages.

@ Async is provided in spring to implement asynchronous methods.

@ Async modifier class, all methods in that class are asynchronous, and @ Async modifier methods are asynchronous.

When the modified method is called, it is executed in a new thread.

In Spring, the method can be called asynchronously by setting the @ Async annotation on the method. That is, the method returns immediately when it is called, and the actual execution of the method is delivered.

To Spring's TaskExecutor to finish it.

1. If the number of threads in the thread pool is less than corePoolSize at this time, even if all the threads in the thread pool are idle, create new threads to handle the added tasks.

two。 If the number of threads in the pool is equal to corePoolSize at this time, but the buffer queue workQueue is not full, the task is placed in the buffer queue.

3. If the number of threads in the pool is greater than corePoolSize, the buffer queue workQueue is full, and the number of threads in the pool is less than maxPoolSize, create new threads to handle the added tasks.

4. If the number in the thread pool is greater than corePoolSize, the buffer queue workQueue is full, and the number in the thread pool is equal to maxPoolSize, then the task is handled through the policy specified by handler. That is, the priority of processing tasks is: core thread corePoolSize, task queue workQueue, and maximum thread maximumPoolSize. If all three are full, use handler to process rejected tasks.

5. When the number of threads in the thread pool is greater than corePoolSize, if a thread is idle longer than keepAliveTime, the thread will be terminated. This way, the thread pool can dynamically adjust the number of threads in the pool.

Record Async usage scenarios this time

Other services need to be called, and the main thread needs to continue to complete the current thread task

Step 1: classes that need to do things

@ Component@EnableSchedulingpublic class VideoStatusUpdateServiceImpl implements VideoStatusUpdateService {@ Resource private VaCaseVideoExtMapper vaCaseVideoExtMapper; / / every five seconds @ Scheduled (cron = "* / 5 *?") @ Override public void videoStatusUpdate () throws IOException {/ / get a collection List list = vaCaseVideoExtMapper.selectAllVideoes () / / iterate through the collection to create an asynchronous thread to do something else for (VaCaseVideo vo: list) {dealTask (vo);} @ Async ("asyncServiceExecutor") public void dealTask (VaCaseVideo vo) throws IOException {System.out.print ("doing something here")}}

Step 2: add @ EnableAsync to the startup class to enable async

@ SpringBootApplication@EnableAsync@EnableCachingpublic class StartApp {public static void main (String [] args) {SpringApplication.run (StartApp.class, args);}}

Step 3: configure Executor (this step is optional, if you do not match the value, the default value will be used), configure custom Executor

@ Configurationpublic class ExecutorConfig {private static final Logger logger = LoggerFactory.getLogger (ExecutorConfig.class); @ Bean public Executor asyncServiceExecutor () {logger.info ("start asyncServiceExecutor"); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor (); / / configure core threads executor.setCorePoolSize (5); / / configure maximum number of threads executor.setMaxPoolSize (60); executor.setKeepAliveSeconds (180) / / configure the queue size executor.setQueueCapacity (60); / / configure the name prefix executor.setThreadNamePrefix ("async-service-") of threads in the thread pool; executor.setRejectedExecutionHandler (new ThreadPoolExecutor.CallerRunsPolicy ()); / / perform initialization executor.initialize (); return executor;}}

Step 4: start the project and print what needs to be done every five seconds

The difference between asynchronous request and asynchronous invocation

The usage scenarios of the two are different. Asynchronous requests are used to solve the pressure caused by concurrent requests on the server, thus improving the throughput of requests, while asynchronous calls are used to do some non-mainline processes and do not require real-time calculation and response, such as synchronous logs to kafka for log analysis.

Asynchronous requests will always wait for the corresponding response and need to return the result to the client. For asynchronous calls, we will often return the response to the client immediately to complete the entire request. As for the tasks invoked asynchronously, the backend will run slowly, and the client will not care.

Implementation of asynchronous request

Method 1: implement asynchronous requests in Servlet mode

@ RequestMapping (value = "/ email/servletReq", method = GET) public void servletReq (HttpServletRequest request, HttpServletResponse response) {AsyncContext asyncContext = request.startAsync (); / / set listeners: you can set callback handling for events such as start, completion, exception, timeout, etc. AsyncContext.addListener (new AsyncListener () {@ Override public void onTimeout (AsyncEvent event) throws IOException {System.out.println ("timeout...") / / do some related operations after timeout.} @ Override public void onStartAsync (AsyncEvent event) throws IOException {System.out.println ("thread start");} @ Override public void onError (AsyncEvent event) throws IOException {System.out.println ("error:" + event.getThrowable ()) } @ Override public void onComplete (AsyncEvent event) throws IOException {System.out.println ("execution complete"); / / you can do some operations to clean up resources here.}}); / / set the timeout asyncContext.setTimeout (20000) AsyncContext.start (new Runnable () {@ Override public void run () {try {Thread.sleep (10000); System.out.println ("Internal Threads:" + Thread.currentThread () .getName ()); asyncContext.getResponse () .setCharacterEncoding ("utf-8") AsyncContext.getResponse (). SetContentType ("text/html;charset=UTF-8"); asyncContext.getResponse (). GetWriter (). Println ("this is an asynchronous request return");} catch (Exception e) {System.out.println ("exception:" + e) } / / Asynchronous request completion Notification / / the entire request is completed at this time asyncContext.complete ();}}); / / Thread connections such as request have released System.out.println ("main thread:" + Thread.currentThread () .getName ());}

Method 2: it is very simple to use the parameters returned directly to wrap a layer of callable. You can inherit the WebMvcConfigurerAdapter class to set the default thread pool and timeout handling.

@ RequestMapping (value = "/ email/callableReq", method = GET) @ ResponseBody public Callable callableReq () {System.out.println ("external thread:" + Thread.currentThread (). GetName ()); return new Callable () {@ Override public String call () throws Exception {Thread.sleep (10000); System.out.println ("internal thread:" + Thread.currentThread (). GetName () Return "callable!";}}; @ Configuration public class RequestAsyncPoolConfig extends WebMvcConfigurerAdapter {@ Resource private ThreadPoolTaskExecutor myThreadPoolTaskExecutor; @ Override public void configureAsyncSupport (final AsyncSupportConfigurer configurer) {/ / processing callable timeout configurer.setDefaultTimeout (60,1000); configurer.setTaskExecutor (myThreadPoolTaskExecutor); configurer.registerCallableInterceptors (timeoutCallableProcessingInterceptor ());} @ Bean public TimeoutCallableProcessingInterceptor timeoutCallableProcessingInterceptor () {return new TimeoutCallableProcessingInterceptor ();}}

Method 3: similar to method 2, in the Callable outsourcing layer, set a timeout callback to WebAsyncTask to achieve timeout processing.

@ RequestMapping (value = "/ email/webAsyncReq", method = GET) @ ResponseBody public WebAsyncTask webAsyncReq () {System.out.println ("external thread:" + Thread.currentThread (). GetName ()); Callable result = ()-> {System.out.println ("Internal thread start:" + Thread.currentThread (). GetName ()); try {TimeUnit.SECONDS.sleep (4) } catch (Exception e) {/ / TODO: handle exception} logger.info ("secondary thread returns"); System.out.println ("internal thread returns:" + Thread.currentThread () .getName ()); return "success";}; WebAsyncTask wat = new WebAsyncTask (3000L, result) Wat.onTimeout (new Callable () {@ Override public String call () throws Exception {/ / TODO Auto-generated method stub return "timeout";}}); return wat;}

Way 4: DeferredResult can handle some relatively complex business logic, the most important thing is that it can carry out business processing and return in another thread, that is, it can communicate between two completely unrelated threads.

@ RequestMapping (value = "/ email/deferredResultReq", method = GET) @ ResponseBody public DeferredResult deferredResultReq () {System.out.println ("external thread:" + Thread.currentThread () .getName ()); / / set the timeout DeferredResult result = new DeferredResult (60Secret1000L) / / result.onTimeout (new Runnable () {@ Override public void run () {System.out.println ("DeferredResult timeout"); result.setResult ("timeout!");}}) is used to handle timeout events. Result.onCompletion (new Runnable () {@ Override public void run () {/ / System.out.println after completion ("call completed");}}) MyThreadPoolTaskExecutor.execute (new Runnable () {@ Override public void run () {/ / processing business logic System.out.println ("internal thread:" + Thread.currentThread (). GetName ()); / / returns the result result.setResult ("DeferredResultbacks!");}}) The use of Asynchronous call in return result;} SpringBoot

1. Introduction

Processing of asynchronous requests. In addition to asynchronous requests, we generally use asynchronous calls. Usually in the development process, you will encounter a method that has nothing to do with the actual business and has no tightness. Such as recording log information and other services. At this time, it is normal to start a new thread to do some business processing, allowing the main thread to execute other businesses asynchronously.

2. Usage mode (based on spring)

You need to add @ EnableAsync to the startup class to make the asynchronous call @ Async annotation effective.

Add this annotation to the method that requires asynchronous execution to @ Async ("threadPool"). ThreadPool is a custom thread pool.

The code is slightly. Just two tags, just try it yourself.

3. Points for attention

By default, when TaskExecutor is not set, the SimpleAsyncTaskExecutor thread pool is used by default, but this thread is not really a thread pool because the thread is not reused and a new thread is created for each call. As can be seen from the console log output, the output thread name is incremented each time. So it's best if we customize a thread pool.

The called asynchronous method cannot be a method of the same class (including the inner class of the same class). To put it simply, because Spring creates a proxy class for it when it starts the scan, and when the same class is called, it still calls its own proxy class, so it is the same as usual.

The same is true for other annotations such as @ Cache. To put it bluntly, it is caused by the proxy mechanism of Spring. Therefore, in development, it is best to extract a separate class to manage the asynchronous service. The following will focus on.

4. Under what circumstances will the @ Async asynchronous method become invalid?

a. Call the same class with @ Async asynchronous method: annotations such as @ Async, @ Transactional and cache in spring essentially use dynamic proxies. In fact, when the Spring container initializes, the Spring container will "replace" the class object containing the AOP annotation with the proxy object (simply understood this way), then the reason for the annotation invalidation is obvious, because the method is called by the object itself, not the proxy object, because it has not gone through the Spring container. Then the solution will also be solved along this line of thinking.

b. The static (static) method is called

c. Call the (private) privatization method

5. The way to solve problem 1 in 4 (just pay attention to the other 2 and 3).

The method to be executed asynchronously is extracted into a separate class. The principle is that when you extract the method that executes asynchronously into a class separately, this class must be managed by Spring, and other Spring components will definitely be injected into it when they need to be called. In fact, what is injected is the proxy class.

In fact, our injected objects assign member variables to the current Spring component from the Spring container. Because some classes use AOP annotations, it is actually its proxy object that actually exists in the Spring container. Then we can get our own proxy object to call asynchronous methods through the context.

@ Controller@RequestMapping ("/ app") public class EmailController {/ / there are many ways to get ApplicationContext objects, which is the simplest. For others, take a look at @ Autowired private ApplicationContext applicationContext; @ RequestMapping (value = "/ email/asyncCall", method = GET) @ ResponseBody public Map asyncCall () {Map resMap = new HashMap () Try {/ / it doesn't work to call the same kind of asynchronous method / / this.testAsyncTask (); / / get your own proxy object through the context to call the asynchronous method EmailController emailController = (EmailController) applicationContext.getBean (EmailController.class); emailController.testAsyncTask (); resMap.put ("code", 200) } catch (Exception e) {resMap.put ("code", 400); logger.error ("error!", e);} return resMap;} / / Note it must be public and the non-static method @ Async public void testAsyncTask () throws InterruptedException {Thread.sleep (10000); System.out.println ("Asynchronous Task execution complete!") ;}}

6. Open the cglib proxy, obtain the Spring proxy class manually, and then call the asynchronous methods under the same class.

First, add the @ EnableAspectJAutoProxy (exposeProxy = true) annotation to the startup class.

The code implementation is as follows:

@ Service@Transactional (value = "transactionManager", readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Throwable.class) public class EmailService {@ Autowired private ApplicationContext applicationContext; @ Async public void testSyncTask () throws InterruptedException {Thread.sleep (10000); System.out.println ("Asynchronous task execution completed!") ;} public void asyncCallTwo () throws InterruptedException {/ / this.testSyncTask (); / / EmailService emailService = (EmailService) applicationContext.getBean (EmailService.class); / / emailService.testSyncTask (); boolean isAop = AopUtils.isAopProxy (EmailController.class); / / whether it is a proxy object; boolean isCglib = AopUtils.isCglibProxy (EmailController.class); / / whether it is a CGLIB proxy object Boolean isJdk = AopUtils.isJdkDynamicProxy (EmailController.class); / / whether it is the proxy object of JDK dynamic proxy mode; / / the following is the key! EmailService emailService = (EmailService) applicationContext.getBean (EmailService.class); EmailService proxy = (EmailService) AopContext.currentProxy (); System.out.println (emailService = = proxy? True: false); proxy.testSyncTask (); System.out.println ("endgame calls!")}} Thank you for reading this article carefully. I hope the article "how to use @ Async Asynchronous calls in Spring" shared by the editor will be helpful to you. At the same time, I hope you will support us and pay attention to the industry information channel. More related knowledge is waiting for you to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report