Home Tags Posts tagged with "@Async"

@Async

场景:现在需要上传一个Excel表格,数据量几万条,而且,上传解析后还需要进行计算,然后插入数据库。

分析:上传和解析,都很简单,但是,这里如果使用同步方式,那么:上传–>解析–>运算–>插入数据库;这个过程,前台的页面都是等待状态的,用户会以为页面卡死了。所以,这里需要做异步处理:

1.上传–>返回正在解析的标志;

2.解析–>运算–>插入数据库;

此时,当用户上传完文件后,页面立马跳转,解析,运算等工作,继续在后台进行,而用户可以不用等待。

 

首先我们需要异步任务在Springboot是如何开启的,这涉及到三个注解:@EnableAsync、@Async、@ComponentScan

使用多线程,往往是创建Thread,或者是实现Runnable接口,用到线程池时还需要创建Executors

@标志开启使用多线程,@Async加在线程任务的方法上(需要异步执行的方法)

@ComponentScan 的作用就是根据定义的扫描路径,把符合扫描规则的类装配到spring容器中

题外话:

注意:@ComponentScan是组件扫描注解,用来扫描@Controller  @Service  @Repository这类,主要就是定义扫描的路径从中找出标志了需要装配的类到Spring容器中

其次,@MapperScan 是扫描mapper类的注解,就不用在每个mapper类上加@Mapper

 

先来看看如果没有异步执行,程序是怎么运行的吧

@Controller
public class DemoCtroller {

    public void Print(){
        for (int i = 0 ;i < 10;i++){
            System.out.println("第"+i+"个");
        }
    }
}
/**
 * 未开启异步任务
 * 顺序执行
 */
//开启定时功能的注解

@SpringBootApplication
@EnableScheduling
public class Application {

 public static void main(String[] args) {

 ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
 context.getBean(DemoCtroller.class).Print();
 for(int i = 0;i <5 ; i++){
 System.out.println("-----------------");
 }

 }

 


}
运行结果:
程序顺序执行,启动类先从IOC容器中获得DemoController的对象然后执行其Print()方法循环打印出9个数字,等到方法结束后才返回启动类继续往下执行,可见整个流程是同步的;
启动类必须先等DemoController的任务完成才能继续向下

异步执行任务,添加@Async注解到要开启异步的方法上

 


运行结果:

 


注意看此处的启动类上的注解:

启动类上没有@EnableAysnc注解,却也调用了异步方法,这是为什么???

原因是@SpringBootApplication是个很强大的注解,它包含了@EnbaleAsync和@ComponentScan两个注解!

我们往启动类的打印方法加入1s的昏睡,使异步行为更清晰

@SpringBootApplication
@EnableScheduling
public class Application {

   public static void main(String[] args) throws InterruptedException {

      ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
      context.getBean(DemoCtroller.class).Print();
      for(int i = 0;i <10; i++){
         TimeUnit.MICROSECONDS.sleep(1);
         System.out.println("-----------------");
      }

   }

}

运行结果:
可见:SpringBoot在获取到IOC中的DemoController对象后,一方面继续往下执行for循环语句,另一方面获取对象后,执行对象中的Print()方法,Print()方法和主线程是异步执行的!!!