Spring Boot 异步任务 -- @Async

Spring Framework 自身提供了对异步任务的支持,本文介绍 Spring Boot 中异步任务开发。

1 定义一个服务类,包含 2 个方法,假设这 2 个方法都非常繁重和耗时。

package demo.spring.boot.async.service;

public interface HeavyService {
    
    void heavy1()
        throws InterruptedException;
    
    void heavy2()
        throws InterruptedException;
}

package demo.spring.boot.async.service.impl;

import demo.spring.boot.async.service.HeavyService;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

@Service
public class HeavyServiceImpl
    implements HeavyService {
    
    @Override
    public void heavy1()
        throws InterruptedException {
        System.out.println("heavy1 started at " + LocalDateTime.now());
        // 模拟方法耗时
        Thread.sleep(3000);
        System.out.println("heavy1 ended at " + LocalDateTime.now());
    }
    
    @Override
    public void heavy2()
        throws InterruptedException {
        System.out.println("heavy2 started at " + LocalDateTime.now());
        // 模拟方法耗时
        Thread.sleep(2000);
        System.out.println("heavy2 ended at " + LocalDateTime.now());
    }
}

2 定义一个定时任务,每隔一段时间调用以上 2 个方法(如何定义定时任务参考:Spring Boot 定时任务 -- @Scheduled)

package demo.spring.boot.async.scheduled;

import demo.spring.boot.async.service.HeavyService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
public class ScheduledTask {
    
    private final HeavyService heavyService;
    
    public ScheduledTask(HeavyService heavyService) {
        this.heavyService = heavyService;
    }
    
    @Scheduled(fixedRate = 10000)
    public void invoke()
        throws InterruptedException {
        System.out.println("invoke started at " + LocalDateTime.now());
        heavyService.heavy1();
        heavyService.heavy2();
    }
}

3 不配置异步任务时执行过程日志如下,从日志中可以看出,heavy1heavy2 这 2 个方法是串行执行的,每次执行完这 2 个任务需耗时 5 秒多。

2018-08-03 21:45:04.108  INFO 18932 --- [           main] d.s.b.a.DemoSpringBootAsyncApplication   : Starting DemoSpringBootAsyncApplication on LAPTOP-C375ASPB with PID 18932 (D:\JYL\DEV\IdeaProjects\demo\demo-spring-boot-async\target\classes started by Ji in D:\JYL\DEV\IdeaProjects\demo)
2018-08-03 21:45:04.112  INFO 18932 --- [           main] d.s.b.a.DemoSpringBootAsyncApplication   : No active profile set, falling back to default profiles: default
2018-08-03 21:45:04.158  INFO 18932 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@53ca01a2: startup date [Fri Aug 03 21:45:04 CST 2018]; root of context hierarchy
2018-08-03 21:45:04.799  INFO 18932 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-08-03 21:45:04.810  INFO 18932 --- [           main] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
2018-08-03 21:45:04.819  INFO 18932 --- [           main] d.s.b.a.DemoSpringBootAsyncApplication   : Started DemoSpringBootAsyncApplication in 0.994 seconds (JVM running for 1.813)
invoke started at 2018-08-03T21:45:04.823
heavy1 started at 2018-08-03T21:45:04.823
heavy1 ended at 2018-08-03T21:45:07.826
heavy2 started at 2018-08-03T21:45:07.826
heavy2 ended at 2018-08-03T21:45:09.835
invoke started at 2018-08-03T21:45:14.823
heavy1 started at 2018-08-03T21:45:14.823
heavy1 ended at 2018-08-03T21:45:17.823
heavy2 started at 2018-08-03T21:45:17.823
heavy2 ended at 2018-08-03T21:45:19.844
......

4 添加异步任务支持

4.1 定义异步配置类

package demo.spring.boot.async.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

@Configuration
@EnableAsync
public class AsyncConfig {
}

4.2 修改 heavy1heavy2 方法,添加 @Async 注释

package demo.spring.boot.async.service.impl;

import demo.spring.boot.async.service.HeavyService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

@Service
public class HeavyServiceImpl
    implements HeavyService {
    
    @Override
    @Async
    public void heavy1()
        throws InterruptedException {
        System.out.println("heavy1 started at " + LocalDateTime.now());
        // 模拟方法耗时
        Thread.sleep(3000);
        System.out.println("heavy1 ended at " + LocalDateTime.now());
    }
    
    @Override
    @Async
    public void heavy2()
        throws InterruptedException {
        System.out.println("heavy2 started at " + LocalDateTime.now());
        // 模拟方法耗时
        Thread.sleep(2000);
        System.out.println("heavy2 ended at " + LocalDateTime.now());
    }
}

4.3 再次启动工程运行定时任务,从日志中可以看出,heavy1heavy2 这 2 个方法是并行执行的,执行完这 2 个任务只耗时 3 秒多,相当于 heavy1 耗时。

2018-08-03 21:47:18.143  INFO 21052 --- [           main] d.s.b.a.DemoSpringBootAsyncApplication   : Starting DemoSpringBootAsyncApplication on LAPTOP-C375ASPB with PID 21052 (D:\JYL\DEV\IdeaProjects\demo\demo-spring-boot-async\target\classes started by Ji in D:\JYL\DEV\IdeaProjects\demo)
2018-08-03 21:47:18.146  INFO 21052 --- [           main] d.s.b.a.DemoSpringBootAsyncApplication   : No active profile set, falling back to default profiles: default
2018-08-03 21:47:18.191  INFO 21052 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@548a102f: startup date [Fri Aug 03 21:47:18 CST 2018]; root of context hierarchy
2018-08-03 21:47:18.847  INFO 21052 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-08-03 21:47:18.859  INFO 21052 --- [           main] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
2018-08-03 21:47:18.867  INFO 21052 --- [           main] d.s.b.a.DemoSpringBootAsyncApplication   : Started DemoSpringBootAsyncApplication in 0.984 seconds (JVM running for 1.708)
invoke started at 2018-08-03T21:47:18.867
2018-08-03 21:47:18.869  INFO 21052 --- [pool-1-thread-1] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either
heavy1 started at 2018-08-03T21:47:18.876
heavy2 started at 2018-08-03T21:47:18.876
heavy2 ended at 2018-08-03T21:47:20.883
heavy1 ended at 2018-08-03T21:47:21.880
invoke started at 2018-08-03T21:47:28.876
heavy1 started at 2018-08-03T21:47:28.877
heavy2 started at 2018-08-03T21:47:28.877
heavy2 ended at 2018-08-03T21:47:30.888
heavy1 ended at 2018-08-03T21:47:31.889
......

@Async 属性

工程目录结构

Spring Boot 异步任务 -- @Async_第1张图片

POM



    4.0.0

    demo.spring.boot
    demo-spring-boot-async
    0.0.1-SNAPSHOT
    jar

    demo-spring-boot-async
    Demo project for Spring Boot

    
        org.springframework.boot
        spring-boot-starter-parent
        2.0.4.RELEASE
         
    

    
        UTF-8
        UTF-8
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


你可能感兴趣的:(Spring Boot 异步任务 -- @Async)