一.前言
使用异步servlet主要原因就是因为,在service方法中业务逻辑如果碰到io操作时间比较长的操作,这样这个service方法就会长时间占用tomcat容器线程池中的线程,这样是不利于其他请求的处理的,当线程池中的线程处理任务时,任务由于长时间io操作,肯定会阻塞线程处理其他任务,引入异步servlet的目的就是将容器线程池和业务线程池分离开。在处理大io的业务操作的时候,把这个操作移动到业务线程池中进行,释放容器线程,使得容器线程处理其他任务,在业务逻辑执行完毕之后,然后在通知tomcat容器线程池来继续后面的操作,这个操作应该是把处理结果commit到客户端或者是dispatch到其他servlet上。原始模型在处理业务逻辑的过程中会一直占有容器线程池,而异步servlet模型,可以看出在业务线程池处理的过程中,有一段时间容器线程池中的那个线程是空闲的,这种设计大大提高了容器的处理请求的能力。
二.DeferredResult的主要原理
- Controller返回一个DeferredResult对象,并且把它保存在内在队列当中或者可以访问它的列表中。
- Spring MVC开始异步处理.
- DispatcherServlet与所有的Filter的Servlet容器线程退出,但Response仍然开放。
- application通过多线程返回DeferredResult中sets值.并且Spring MVC分发request给Servlet容器.
- DispatcherServlet再次被调用并且继续异步的处理产生的结果.
三.示例
1.申明两个方法接口,模拟用户登录接口
public interface DeferredResultServiceInter {
TResult login();
void login1(DeferredResult<TResult<User>> deferredResult);
}
2.接口实现类
@Service
public class DeferredResultServiceImpl implements DeferredResultServiceInter {
@Override
public TResult login() {
TResult<User> result = new TResult<>();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
User user = new User();
user.setPassword("123");
user.setUsername("456");
result.setModel(user);
return result;
}
@Override
public void login1(DeferredResult<TResult<User>> deferredResult) {
TResult<User> result = new TResult<>();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
User user = new User();
user.setPassword("123");
user.setUsername("456");
result.setModel(user);
String jsonString = JSONObject.toJSONString(result);
deferredResult.setResult(result);
}
}
3.controller方法
@RestController
public class SynController {
private Logger logger = LoggerFactory.getLogger(SynController.class);
@Resource
DeferredResultServiceInter deferredResultServiceInter;
ExecutorService executors= Executors.newCachedThreadPool();
@GetMapping("/login")
@Log
public TResult<User> login() {
TResult login = deferredResultServiceInter.login();
return login;
}
@GetMapping("/login1")
@Log
public Callable<TResult<User>> login1() {
Callable<TResult<User>> result = (() -> {
return deferredResultServiceInter.login();
});
return result;
}
@GetMapping("/login2")
@Log
public DeferredResult<TResult<User>> login2() {
DeferredResult<TResult<User>> deferredResult = new DeferredResult<>(5000L, "---请求超时---");
executors.submit(new Runnable() {
@Override
public void run() {
System.out.println("=====异步线程开始===="+System.currentTimeMillis());
deferredResultServiceInter.login1(deferredResult);
System.out.println("=====异步线程结束===="+System.currentTimeMillis());
}
});
return deferredResult;
}
}
结果:
(1)调用/login
类名称:com.example.springbootTest.controller.SynController
方法名:login
执行时间:3000毫秒
(2)调用login1
类名称:com.example.springbootTest.controller.SynController
方法名:login1
执行时间:0毫秒
(3)调用login2
类名称:com.example.springbootTest.controller.SynController
方法名:login2
执行时间:0毫秒
异步线程开始====1542945731423
异步线程结束 1542945734425
三个结果都是
{“errorCode”:0,“model”:{“id”:0,“username”:“456”,“password”:“123”,“salt”:null},“list”:null}