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;
    }
  2. 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);
    }
    }
  3. 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();
    }
    }
  4. 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);
    }
    }
    }
  5. 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

许可协议

评论