应用场景 :举个栗子:一般在项目开发中都会有登录成功失败记录日志,或者记录操作日志的需求,如果不采用异步记录的方式,多少会影响接口的效率,故采用异步的方式记录
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();
}
}
}
模拟操作:假装自己登陆失败啦
模拟返回给用户message:你登录失败啦
开始任务三:暴打产品经理
开始任务二:记录操作日志
开始任务一:记录登录日志
模拟操作:假装自己登陆失败啦
模拟返回给用户message:你登录失败啦
开始任务一:记录登录日志
开始任务二:记录操作日志
开始任务三:暴打产品经理
1.本人在第一次测试时,直接将异步执行的方法和测试类写到一起,发现并没有按照预期的执行结果打印.简单来说,因为Spring在启动扫描时会为其创建一个代理类,而同类调用时,还是调用本身的代理类的,所以和平常调用是一样的。其他的注解如@Cache等也是一样的道理,说白了,就是Spring的代理机制造成的。
2.还有个问题不知道大家看到没有,异步方法中执行完之后的输出没有打印
System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
这是因为这三个异步任务,同时开始执行,而异步不在spring的生命周期范围之内,所以测试类默认当前实例已经销毁,故不会再进行打印,如果需要操作带有返回值的异步任务,需要使用Futrue(回调函数)进行封装