场景:微信公众号授权页面,公众号所有者扫码授权时,拉取公众号下的粉丝信息,完成后跳转至授权成功页面。
问题:当粉丝数量很大的时候,拉取用户信息(包括网络请求)耗时很长,授权页面会因为请求超时挂掉。(很多耗时操作都要考虑到用户体验,先返回授权成功页面,耗时操作在异步执行)
解决方法:异步执行耗时的拉取用户信息操作。SpringBoot中直接可以@Async注解实现异步调用。
@Controller
@RequestMapping("/open/auth")
public class AuthCallbackController extends SuperController {
@RequestMapping("/callbacktest")
public String callback()throws Exception{
new CoreTask().task1();
new CoreTask().task2();
new CoreTask().task3();
return "auth/authSuccess";
}
}
CoreTask类,执行测试的三个方法上加上注解@Async:
@Component
public class CoreTask {
@Async
public void task1()throws Exception{
Thread.sleep(1000);
System.out.println("我是任务1");
}
@Async
public void task2()throws Exception{
Thread.sleep(2000);
System.out.println("我是任务2");
}
@Async
public void task3()throws Exception{
Thread.sleep(3000);
System.out.println("我是任务3");
}
}
SpringBoot启动主类Application类也要加上注解@EnableAsync
启动项目,通过浏览器访问open/auth。
异步执行不是按照顺序依次执行的,而且授权成功页面不用等方法都执行完才请求到。
访问结果依然是依次执行,授权成功页面也是方法执行完才显示。
百度找解决方法。
异步并没有执行!
难道是代码写错了?反复检查了好几遍,并没有发现什么明显错误,想起spring对@Transactional注解时也有类似问题,spring扫描时具有@Transactional注解方法的类时,是生成一个代理类,由代理类去开启关闭事务,而在同一个类中,方法调用是在类体内执行的,spring无法截获这个方法调用。
百度找到的这个答案和我遇到的问题并不一样,他遇到的这种情况是在当前的类中调用异步方法。
在同一个类中,方法调用是在类体内执行的,spring无法截获这个方法调用。
我突然想起来我是new来实例化CoreTask类的,然后调用其中的异步方法。问题可能出在这里,spring无法拦截实例化的这个类的方法调用。
于是,在Controller中添加,然后调用异步方法:
@Autowired
private CoreTask coreTask;
------------------------------
coreTask.task1();
coreTask.task2();
coreTask.task3();
重启,异步执行成功。授权成功页面在请求的第一时间就刷新出来,并没有等到异步方法都执行完。