Spring MVC Servlet 3.0+ 异步方法实现服务端的消息推送

Servlet 3.0+ 异步方法实现服务端消息推送是通过使用定时任务,定时的让控制器从另外一个线程返回一个DeferedResult并推送给客户端。而更新DeferedResult是在使用@Scheduled定时任务注解的方法里执行的。

示例

Maven管理的项目,pom.xml添加Servlet 3.0+版本依赖包。

  1. SpringMvcConfig.java类上添加开启定时任务的注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
@EnableWebMvc
@EnableScheduling//开启计划任务
@ComponentScan(basePackages = {"com"})
public class SpringMvcConfig extends WebMvcConfigurerAdapter {

/**
* 配置viewResolver,用来映射来物理路径
* @return
*/
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(JstlView.class);
return viewResolver;
}
  1. Web初始化类时添加开启Servlet3.0+异步方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* WebApplicationInitializer是Spring提供用来配置Servlet+3.0配置的接口,从而实现了替代web.xml的位置。
* 实现该接口会自动被SpringServletContainerInitializer(用来启动Servlet3.0容器)获取到。
* @author Rocky
*
*/

public class WebInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {

//注解方式配置的web上下文
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(SpringMvcConfig.class);
//将上下文和当前servletContext关联
context.setServletContext(servletContext);
//注册dispatcher
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
//Servlet3.0支持开启异步方法
servlet.setAsyncSupported(true);
}
}
  1. Controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Controller
public class AysncController {

@Autowired
PushServiceImpl pushServiceImpl;

@RequestMapping("/async")
public String asyncPage() {
return "async";
}

@RequestMapping("/defer")
@ResponseBody
public DeferredResult<String> deferredCall() {
return pushServiceImpl.getAsyncUpdate();
}
}
  1. Service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Service
public class PushServiceImpl {

private DeferredResult<String> deferredResult;

public DeferredResult<String> getAsyncUpdate(){
deferredResult = new DeferredResult<>();
return deferredResult;
}

//定时任务,每5秒执行一次
@Scheduled(fixedDelay = 5000)
public void refresh() {

if(deferredResult != null) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateTime = sdf.format(System.currentTimeMillis());
deferredResult.setResult("NowDateTime: " + dateTime);
}
}
}
  1. jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<script type="text/javascript"
src="${pageContext.request.contextPath}/static/js/jquery-1.11.0.js"></script>

<script type="text/javascript">
var s = '';
deferred();

function deferred() {

$.get('defer', function(data) {
console.log(data);
s = s + (data + "<br/>");
$("#msgFromPush").html(s);
deferred();
})
}
</script>

<title>SSE Demo</title>
</head>
<body>
<div id="msgFromPush"></div>
</body>
</html>

参考资料

Servlet 3特性:异步Servlet
tomcat servlet3的异步化原理理解

Spring MVC Servlet 3.0+ 异步方法实现服务端的消息推送

http://blog.gxitsky.com/2018/04/01/SpringMVC-25-Servlet-v3-AsyncMethod/

作者

光星

发布于

2018-04-01

更新于

2022-06-17

许可协议

评论