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

Example Analysis of Spring Boot Asynchronous request and Asynchronous call

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

Share

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

This article mainly shows you "sample Analysis of Spring Boot Asynchronous request and Asynchronous call", which is easy to understand and clear. I hope it can help you solve your doubts. Let the editor lead you to study and learn the article "sample Analysis of Spring Boot Asynchronous request and Asynchronous call".

I. the use of asynchronous requests in Spring Boot

1. Asynchronous request and synchronous request

Features:

You can first release the request thread and related resources assigned by the container, lighten the burden on the system, release the request from the thread assigned by the container, and the response will be delayed. You can respond to the client when the time-consuming processing is completed (such as a long operation).

Bottom line: increased the throughput of the server to the client request (we use less in actual production. If the number of concurrent requests is large, we will load the request to each node of the cluster service through nginx to share the request pressure. Of course, we can also buffer the request through message queue).

2. 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 asyncContext.addListener (new AsyncListener () {@ Override public void onTimeout (AsyncEvent event) throws IOException {System.out.println ("timeout...") for its start, completion, exception, timeout and other events. / / 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 occurs:" + 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 thread:" + 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 Threads:" + 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 ("DeferredResultkeeper!") }}); return result;}

2. The use of asynchronous calls in Spring Boot

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 comment to the method that needs to be executed asynchronously to @ Async ("threadPool"), where 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?

Call the @ Async asynchronous method on the same class:

Annotations such as @ Async, @ Transactional and cache in spring essentially use dynamic proxies. In fact, when initializing the Spring container, the Spring container will "replace" the class object containing the AOP annotation with the proxy object (simply understood this way), so the reason for the annotation failure 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.

The static (static) method is called

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 completed!") ;}}

Open the cglib proxy and manually obtain the Spring proxy class, thus calling 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 ("endlessly installed!");}}

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.

The above is all the contents of the article "sample Analysis of Spring Boot Asynchronous requests and Asynchronous invocations". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!

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