Spring Boot from entry to actual combat (X): asynchronous processing

Original Address: http://blog.jboost.cn/2019/07/22/springboot-async.html

 

In business development, sometimes encounter some additional non-core functions, such as SMS or micro-message notification letter template, or a number of relatively long time-consuming, but the main process does not require immediate access to the operating result of feedback, such as saving images, synchronized data to other partners like. If these operations are placed in the main flow synchronization process, will inevitably affect the performance of core processes, and even third-party service due to a problem leads to self-service is unavailable. This time should these operations Asynchronized to improve the performance of the primary process, and decoupled with third parties to improve the availability of the primary process.

In Spring Boot in, or in the Spring, we realize asynchronous processing generally have the following ways:

1. @EnableAsync by binding achieved with @Asyc annotation
2. achieved by asynchronous events
3. achieved through the message queue

1. annotation-based realization

We used to provide asynchronous support in Spring is generally added in the configuration file similar to the following configuration in applicationContext.xml

<task:annotation-driven executor="executor" />
<task:executor id="executor" pool-size="10-200" queue-capacity="2000"/>

 

Spring @EnableAsync annotation function and <task:annotation-driven/>the like, which is added to a class @Configuration configuration, openable support asynchronous method Spring application context. @Async notes can be marked on the method or class that represents a method or a class of all the methods needed to call asynchronously. 

We have a demo for example the specific use, demo Address: https://github.com/ronwxy/springboot-demos/tree/master/springboot-async

 

1. Add @EnableAsync comment

Add @EnableAysnc comment on a @Configuration configuration class, we generally can be added to the startup class, such as

@SpringBootApplication
@EnableAsync
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

 

2. Configure related asynchronous execution thread pool 

@Configuration
public class AsyncConfig implements AsyncConfigurer {


    @Value("${async.corePoolSize:10}")
    private int corePoolSize;

    @Value("${async.maxPoolSize:200}")
    private int maxPoolSize;

    @Value("${async.queueCapacity:2000}")
    private int queueCapacity;

    @Value("${async.keepAlive:5}")
    private int keepAlive;

    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAlive);
        executor.setThreadNamePrefix("async-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setDaemon(false); //以用户线程模式运行
        executor.initialize();
        return executor;
    }

    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new MyAsyncUncaughtExceptionHandler();
    }

    public static class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {

        public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
            System.out.println("catch exception when invoke " + method.getName());
            throwable.printStackTrace();
        }
    }
}

 

Class can be configured by way of asynchronous thread pool configuration, and a processing method of an exception when executed asynchronously, such as

Here we provide an interface by implementing AsyncConfigurer an asynchronous execution thread pool object, indicating that each parameter can refer to [ the basic principles of the thread pool, to understand the reading ], there are very detailed introduction. And it provides a process of handling an asynchronous implementation class uncaught exception AsyncUncaughtExceptionHandler by implementing the interface. 

 

3. Define the asynchronous method

Only asynchronous method defined in class (the class represents all annotations are asynchronous execution of class methods) to add annotations or @Async the method, such as

@Service
public class AsyncService {

    @Async
    public void asyncMethod(){
        System.out.println("2. running in thread: " + Thread.currentThread().getName());
    }

    @Async
    public void asyncMethodWithException() {
        throw new RuntimeException("exception in async method");
    }
}

 

4. Test 

We can test the asynchronous method by the following test class

@RunWith(SpringRunner.class)
@SpringBootTest
public class AnnotationBasedAsyncTest {

    @Autowired
    private AsyncService asyncService;

    @Test
    public void testAsync() throws InterruptedException {
        System.out.println("1. running in thread: " + Thread.currentThread().getName());
        asyncService.asyncMethod();

        Thread.sleep(3);
    }

    @Test
    public void testAysncWithException() throws InterruptedException {
        System.out.println("1. running in thread: " + Thread.currentThread().getName());
        asyncService.asyncMethodWithException();

        Thread.sleep(3);
    }
}

Because the asynchronous method is executed in a new thread, it may be not enough time to deal with the main thread after the implementation, it is executed by a sleep to wait for it to complete. In particular the results of the reader can try to run on their own, there is not a map.

 

2. Based on the realization of events

The second way is achieved by the event listener mechanism Spring Framework, Spring default event listener is executed synchronously, so in fact still need to implement asynchronous with the aid of @EnableAsync @Async.

1. Add @EnableAsync comment

And the same can be added to the startup class.

2. Custom Event class
by inheriting from ApplicationEvent define an event

public class MyEvent extends ApplicationEvent {

    private String arg;

    public MyEvent(Object source, String arg) {
        super(source);
        this.arg = arg;
    }
    
    //getter/setter
}

 

3. Define the event handler class
supports two forms, one ApplicationListener by implementing the interface, as follows

@Component
@Async
public class MyEventHandler implements ApplicationListener<MyEvent> {

    public void onApplicationEvent(MyEvent event) {
        System.out.println("2. running in thread: " + Thread.currentThread().getName());
        System.out.println("2. arg value: " + event.getArg());
    }
}

Second, through @EventListener annotation, as

@Component
public class MyEventHandler2 {

    @EventListener
    @Async
    public void handle(MyEvent event){
        System.out.println("3. running in thread: " + Thread.currentThread().getName());
        System.out.println("3. arg value: " + event.getArg());
    }
}

Note that both need to add @Async notes, otherwise the default is to perform a synchronized manner. 

 

4. The class defines the event transmission
can be achieved by using publishEvent ApplicationEventPublisher ApplicationEventPublisherAware interface () method sends the event,

@Component
public class MyEventPublisher implements ApplicationEventPublisherAware {

    protected ApplicationEventPublisher applicationEventPublisher;

    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    public void publishEvent(ApplicationEvent event){
        this.applicationEventPublisher.publishEvent(event);
    }
}

 

 

5. Test

 

It can be tested by a test class,

@RunWith(SpringRunner.class)
@SpringBootTest
public class EventBasedAsyncTest {

    @Autowired
    private MyEventPublisher myEventPublisher;

    @Test
    public void testAsync() throws InterruptedException {
        System.out.println("1. running in thread: " + Thread.currentThread().getName());
        myEventPublisher.publishEvent(new MyEvent(this,"testing event based async"));
        Thread.sleep(3);
    }
}

 

After running event handlers found two classes are implemented, as both monitor the same event MyEvent. 

 

3. Based on the message queue

Above two methods are based on the machine running the server, if the server process abnormal exit, may cause asynchronous execution interruption. If you need to ensure the reliability of task execution, persistence can make use of the message queue and retry mechanism. Message Queuing service on Ali cloud provides several types of messaging support, such as the order of the message, timer / delay information, transaction information, etc. (For details, please refer to: https://help.aliyun.com/document_detail/29532.html? = 5176.234368.1278132.btn4.6f43db25Rn8oey SPM  ), if the project is based on Ali cloud deployments, consider using one type of messaging services to achieve business needs.

 

4. Summary

Several methods herein for asynchronous processing of the spring boot are introduced, if the reliability is less demanding task execution, the first approach is recommended, if higher reliability is recommended for self cloud message queue or way message Queuing service.
This article demo Source Address: https://github.com/ronwxy/springboot-demos/tree/master/springboot-async/src/main/java/cn/jboost/async


my personal blog address: HTTP: // Blog. jboost.cn
my micro-channel public number: jboost-ksxy (a technique not only dry numbers of the public are welcome attention, timely access to
updates) -------------------- -------------------------------------------
Micro-channel public number

Guess you like

Origin www.cnblogs.com/spec-dog/p/11229633.html