springboot之异步任务,暴打产品???

springboot异步任务

应用场景 :举个栗子:一般在项目开发中都会有登录成功失败记录日志,或者记录操作日志的需求,如果不采用异步记录的方式,多少会影响接口的效率,故采用异步的方式记录

  • springboot2.x中异步的使用:
  • 异步的方法均位于org.springframework.scheduling.annotation

1.创建springboot项目
2.在启动类添加注解@EnableAsync

@SpringBootApplication
@ServletComponentScan
@EnableWebSocket
@EnableScheduling
@EnableAsync	 //开启异步任务
public class GunsApplication {

   public static void main(String[] args) {
       System.setProperty("es.set.netty.runtime.available.processors", "false");
       SpringApplication.run(GunsApplication.class, args);
   }
}

2.编写需要异步处理的业务

// 模拟异步业务
@Component
public class AnyscTask {
    public static Random random =new Random();
    @Async
    public void doTaskOne() throws Exception {
        System.out.println("开始任务一:记录登录日志");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
    }
    @Async
    public void doTaskTwo() throws Exception {
        System.out.println("开始任务二:记录操作日志");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
    }
    @Async
    public void doTaskThree() throws Exception {
        System.out.println("开始任务三:暴打产品经理");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
    }
}
  • 可以看到在需要异步执行的方法加上 注解@Async 该方法就会变成异步方法,是不是很简单:)

  • 测试类测试

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Slf4j
public class MessageQueue {
   @Autowired
   private AnyscTask anysc;
   @Test
   public void aysncTest(){
       try {
           System.out.println("模拟操作:假装自己登陆失败啦");
           this.anysc.doTaskOne();
           this.anysc.doTaskTwo();
           this.anysc.doTaskThree();
           System.out.println("模拟返回给用户message:你登录失败啦");
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}
  • 执行以上代码后console打印为:
模拟操作:假装自己登陆失败啦
模拟返回给用户message:你登录失败啦
开始任务三:暴打产品经理
开始任务二:记录操作日志
开始任务一:记录登录日志
  • 第二次执行
模拟操作:假装自己登陆失败啦
模拟返回给用户message:你登录失败啦
开始任务一:记录登录日志
开始任务二:记录操作日志
开始任务三:暴打产品经理
  • 通过上面的测试我们可以发现模拟接口会先返回给用户登录失败的状态,再去记录登录失败等一系列操作,这样用户就会第一时间知道自己操作失败,体验提升大大的

**注意**:

1.本人在第一次测试时,直接将异步执行的方法和测试类写到一起,发现并没有按照预期的执行结果打印.简单来说,因为Spring在启动扫描时会为其创建一个代理类,而同类调用时,还是调用本身的代理类的,所以和平常调用是一样的。其他的注解如@Cache等也是一样的道理,说白了,就是Spring的代理机制造成的。

2.还有个问题不知道大家看到没有,异步方法中执行完之后的输出没有打印

System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");

这是因为这三个异步任务,同时开始执行,而异步不在spring的生命周期范围之内,所以测试类默认当前实例已经销毁,故不会再进行打印,如果需要操作带有返回值的异步任务,需要使用Futrue(回调函数)进行封装

  • 下个文章我会记录一下Futrue回调函数的使用,还有在Springboot中如何优化异步任务池等
  • 第一次写文章,写的不好的地方请多包涵
  • 如果有阅读量的话后续本人还有持续更新一些Java,SpringBoot,SpringCloud,Redis,Elasticsearch等一些java后端技术干货

你可能感兴趣的:(springboot干货)