Spring容器初始化的时候如何添加一个定时器?
昨天遇到这个问题,在项目启动的时候添加一个定时器隔一段时间扫描有没有定时发送的邮件(当然也可以是你自己的业务逻辑),也在网上找了资料,加上自己的修改,终于成功了。所以来做个记录。
1、ServletContextListener
我们需要在web容器启动的时候,就添加自己的业务。那么有没有一个类或接口能监听web容器的生命周期呢?当然是有的,在Servlet API 中有一个 ServletContextListener 接口,它能够监听 ServletContext 对象的生命周期,也就满足我们的要求。
2、WebApplicationContext
ApplicationContext是Spring的核心,Context我们通常解释为上下文环境,我想用“容器”来表述它更容易理解一些,ApplicationContext则是“应用的容器”了;在Web应用中,我们会用到WebApplicationContext,WebApplicationContext继承自ApplicationContext;WebApplicationContext的初始化方式和BeanFactory.ApplicationContext有所区别,因为WebApplicationContext需要ServletContext实例,也就是说它必须拥有Web容器的前提下才能完成启动的工作。
3、Java代码:
1 package com.defer.mail.util; 2 3 import java.util.Date; 4 import java.util.List; 5 import java.util.Timer; 6 import java.util.TimerTask; 7 import javax.servlet.ServletContextEvent; 8 import javax.servlet.ServletContextListener; 9 import org.springframework.web.context.WebApplicationContext; 10 import org.springframework.web.context.support.WebApplicationContextUtils; 11 import com.defer.mail.domain.Email; 12 import com.defer.mail.domain.User; 13 import com.defer.mail.service.EmailService; 14 import com.defer.mail.service.UserService; 15 public class SendEmailTimer implements ServletContextListener{ 16 17 18 private Timer timer = null; 19 20 /** 21 * @Name: contextInitialized 22 * @Description:容器初始化 23 **/ 24 @Override 25 public void contextInitialized(ServletContextEvent event) { 26 //通过给spring的WebApplicationContextUtils传入ServletContext的监听对象来获取获取当前的web容器 27 WebApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(event.getServletContext()); 28 //创建定时器 29 timer = new Timer(true); 30 System.out.println("定时器已经启动"); 31 //设定每7200秒查询一次是否有定时发送邮件 32 timer.schedule(new QuerySendEmail(ac), 0, 7200*1000); 33 System.out.println("已经添加查询任务"); 34 } 35 36 /** 37 * ClassName: QuerySendEmail 38 * @Description: 业务类,继承TimerTask类,添加自己的业务 39 */ 40 private static class QuerySendEmail extends TimerTask { 41 private static boolean isRunning = false; 42 private WebApplicationContext context = null; 43 44 public QuerySendEmail(WebApplicationContext context) { 45 this.context = context; 46 } 47 48 @SuppressWarnings("static-access") 49 @Override 50 public void run() { 51 if(!isRunning) { 52 isRunning = true; 53 // TODO 自己的业务流程 54 EmailService emailService = (EmailService) context.getBean("emailServiceImpl"); 55 UserService userService = (UserService) context.getBean("userServiceImpl"); 56 List<Email> emailList = emailService.findNoSendEmail(); 57 if(emailList != null && emailList.size() >0) { 58 for (Email email : emailList) { 59 User user = userService.getById(email.getUser().getId()); 60 String fromUser = user.getEmail(); 61 String code = email.getCode(); 62 String topic = email.getTopic(); 63 String content = email.getContent(); 64 String toUser = email.getToUser(); 65 SendEmail sendEmail = new SendEmail(); 66 boolean status = false; 67 while(status==false) { 68 69 status = sendEmail.sendEmail(fromUser, toUser, code, topic, content); 70 if(status) { 71 email.setStatus("1"); //设置邮件状态为已发送 72 email.setSendDate(new Date()); //设置发送时间 73 emailService.update(email); 74 status = true; 75 System.out.println("发送成功========="); 76 } else { 77 status = false; 78 System.out.println("发送失败========="); 79 } 80 81 } 82 } 83 } else { 84 System.out.println("没有定时邮件"); 85 } 86 87 isRunning = false; 88 System.out.println("查询结束"); 89 } else { 90 System.out.println("上一次查询还未结束"); 91 } 92 93 } 94 95 } 96 97 /** 98 * 99 * @Name: contextDestroyed 100 * @Description:容器销毁 101 */ 102 @Override 103 public void contextDestroyed(ServletContextEvent servletcontextevent) { 104 // TODO Auto-generated method stub 105 106 } 107 108 109 }
4、虽然该类实现了ServletContextListener接口,如何让spring容器加载的时候能初始化该类中的操作呢?那肯定少不了配置spring的配置文件
1 <!-- 用于定时器工作的监听器。配置在spring的ContextLoaderListener之后,因为需要用到spring的容器对象 --> 2 <listener> 3 <listener-class> 4 <!-- 自己的类路径 --> 5 com.defer.mail.util.SendEmailTimer 6 </listener-class> 7 </listener>
5、测试成功
stay hungry,stay foolish