Tomcat启动完毕后启动方法任务

Tomcat启动完成后再执行一个指定的方法 - 不影响Tomcat的启动时间

本文主要介绍Tomcat启动真正完成后(即在eclipse的控制台上出现类似于Server started in 2300ms这样的消息后)执行一个操作。 
如下的3种方法都是在Tomcat启动过程中执行的,这样会影响Tomcat的启动时间,从而造成Tomcat不能启动成功:  
1.配置一个Servlet默认自动启动。  
2.配置一个Listener来启动  
3.实现Spring的InitializingBean接口  
要想不影响Tomcat的启动,便联想到了异步调用 。即无非就是新创建了一个线程来单独执行,这样Tomcat执行到相应的操作就可以直接继续下去了,不会处于等待的状态,避免了启动超时。基于这样的思想,可以有两种方法来完成:

方法一: 使用如上三种方式中的任何一种来在启动Tomcat的过程中执行相应的方法,然后在执行的过程中使用另一个线程来执行:比如说将要执行的方法所在的类继承HttpServlet并在web.xml中配置,然后在该Servlet的init中去调用想要执行的方法时(假设这个方法名叫start()),启动另一个线程来执行,具体代码如下。

[java]  view plain  copy
  1. package com.cc.ovp.web.video;  
  2.   
  3.   
  4. import static com.cc.ovp.util.RedisUtils.getPool;  
  5.   
  6. import java.util.List;  
  7. import java.util.concurrent.Callable;  
  8. import java.util.concurrent.FutureTask;  
  9.   
  10. import javax.annotation.Resource;  
  11.   
  12. import javax.servlet.ServletContextEvent;  
  13. import javax.servlet.ServletContextListener;  
  14. import javax.servlet.ServletException;  
  15. import javax.servlet.http.HttpServlet;  
  16.   
  17. import org.slf4j.Logger;  
  18. import org.slf4j.LoggerFactory;  
  19. import org.springframework.stereotype.Controller;  
  20.   
  21. import redis.clients.jedis.Jedis;  
  22. import ayou.util.DOC;  
  23. import ayou.util.StringUtil;  
  24.   
  25. import com.cc.ovp.dao.M3u8ContentDAO;  
  26. import com.cc.ovp.dao.M3u8_db;  
  27. import com.cc.ovp.domain.M3u8Content;  
  28. import com.cc.ovp.service.MongoSearchService;  
  29. import com.cc.ovp.util.JsonUtil;  
  30. import com.cc.ovp.util.Pager;  
  31.   
  32.   
  33. /** 
  34.  * 定时清理一下videojson 的redis缓存 
  35.  * 需求: 
  36.  * 查询m3u8_content的status字段不为8, 
  37.  * 就清除redis 缓存,重新set值到redis, 
  38.  * cleanRedisVideoJSon(String vid), 
  39.  * 更新m3u8_content的status 字段为8 
  40.  */  
  41. @Controller  
  42. public class CleanVideoJsonRedis extends HttpServlet{  
  43.       
  44.     private static final Logger logger = LoggerFactory.getLogger(CleanVideoJsonRedis.class);  
  45.       
  46.     private final int sleepTime=5*60*1000;  
  47.       
  48.     @Resource(name = "m3u8ContentDAO")  
  49.     private M3u8ContentDAO m3u8ContentDAO;  
  50.       
  51.     @Resource(name="videoJson")  
  52.     private VideoJson videoJson;  
  53.       
  54.       
  55.     // Servlet的init方法会在Tomcat启动的时候执行  
  56.     @Override  
  57.     public void init() throws ServletException {  
  58.       FutureTask task = new FutureTask(new Callable(){  
  59.            @Override  
  60.            public String call() throws Exception {  
  61.                taskstart(); //使用另一个线程来执行该方法,会避免占用Tomcat的启动时间  
  62.               return "Collection Completed";  
  63.            }  
  64.       });  
  65.         
  66.       new Thread(task).start();;  
  67.     }  
  68.   
  69.       
  70.     public void taskstart(){  
  71.         while (true) {  
  72.             try {  
  73.                 System.out.println("init");  
  74.                 System.out.println("==============================");  
  75.                 Thread.sleep(5*1000);  
  76.                 Pager pager = new Pager(1200);  
  77.               pager.setSortname("dateAdded");  
  78.               pager.setSortorder("desc");  
  79.               List list = m3u8ContentDAO.findList(pager);  
  80.               System.out.println("=============================="+list.size());  
  81.                 logger.info("tomcat 测试方法");  
  82.             } catch (InterruptedException e) {  
  83.                 // TODO Auto-generated catch block  
  84.                 e.printStackTrace();  
  85.             }  
  86.               
  87.         }  
  88.     }  
  89.   
  90. }  

web.xml配置文件增加一个serlvet

[html]  view plain  copy
  1. <servlet>  
  2.    <servlet-name>event-collectorservlet-name>  
  3.    <servlet-class>com.cc.ovp.web.video.CleanVideoJsonRedisservlet-class>  
  4.    <load-on-startup>60load-on-startup>  
  5.  servlet>  
  6.    
  7.  <servlet-mapping>  
  8.    <servlet-name>event-collectorservlet-name>  
  9.    <url-pattern>/event-collecturl-pattern>  
  10.  servlet-mapping>  


方法二: 配置一个Listener来启动  

web.xml

[html]  view plain  copy
  1.   
  2. <listener>  
  3.     <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>  
  4. listener>  
  5.   
  6.    <listener>  
  7.     <listener-class>com.cc.ovp.web.video.CleanVideoJsonRedislistener-class>  
  8. listener>  

注意: 标签一定要在之后,在之前配置

[java]  view plain  copy
  1. 2。CleanVideoJsonRedis.java  
  2. package myservlet;  
  3. import javax.servlet.*;  
  4. import java.util.*;  
  5. public class CleanVideoJsonRedis implements ServletContextListener{  
  6.   
  7. public CleanVideoJsonRedis(){  
  8.    System.out.println("调用了构造方法");  
  9. }  
  10. public void contextInitialized(ServletContextEvent event) {  
  11.    System.out.println(" ----------创建了Context created on " +  
  12.    new Date() + ".");  
  13.    }  
  14.    public void contextDestroyed(ServletContextEvent event) {  
  15.    System.out.println("--------销毁了Context destroyed on " +  
  16.    new Date() + ".");  
  17.    }  
  18.   
  19. }  
  20. 说明:listener 配置在web.xml中,当web服务启动时,会实例化class/>中指定的类,所以里面一定要写完整类路径.  



方法三: 使用Spring的Timer或者是著名的Quartz在Tomcat启动后再执行该方法,Spring中的Timer非常简单,这个地方不想讲解了,Quartz相对更复杂些,下面主要介绍下在Spring中怎么样使用Quartz来实现上面的需求:

例子:

[java]  view plain  copy
  1. package com.cc.ovp.web.video;  
  2.   
  3.   
  4. import static com.cc.ovp.util.RedisUtils.getPool;  
  5.   
  6. import java.util.List;  
  7. import java.util.concurrent.Callable;  
  8. import java.util.concurrent.FutureTask;  
  9.   
  10. import javax.annotation.Resource;  
  11. import javax.servlet.ServletContextEvent;  
  12. import javax.servlet.ServletContextListener;  
  13. import javax.servlet.ServletException;  
  14. import javax.servlet.http.HttpServlet;  
  15.   
  16. import org.quartz.Job;  
  17. import org.quartz.JobExecutionContext;  
  18. import org.quartz.JobExecutionException;  
  19. import org.slf4j.Logger;  
  20. import org.slf4j.LoggerFactory;  
  21. import org.springframework.stereotype.Controller;  
  22.   
  23. import redis.clients.jedis.Jedis;  
  24. import ayou.util.DOC;  
  25. import ayou.util.StringUtil;  
  26.   
  27. import com.cc.ovp.dao.M3u8ContentDAO;  
  28. import com.cc.ovp.dao.M3u8_db;  
  29. import com.cc.ovp.domain.M3u8Content;  
  30. import com.cc.ovp.service.MongoSearchService;  
  31. import com.cc.ovp.util.JsonUtil;  
  32. import com.cc.ovp.util.Pager;  
  33.   
  34.   
  35. /** 
  36.  * 定时清理一下videojson 的redis缓存 
  37.  * 需求: 
  38.  * 查询m3u8_content的status字段不为8, 
  39.  * 就清除redis 缓存,重新set值到redis, 
  40.  * cleanRedisVideoJSon(String vid), 
  41.  * 更新m3u8_content的status 字段为8 
  42.  */  
  43. @Controller  
  44. public class CleanVideoJsonRedis implements Job{  
  45.       
  46.     private static final Logger logger = LoggerFactory.getLogger(CleanVideoJsonRedis.class);  
  47.       
  48.     private final int sleepTime=5*60*1000;  
  49.       
  50.     @Resource(name = "m3u8ContentDAO")  
  51.     private M3u8ContentDAO m3u8ContentDAO;  
  52.       
  53.     @Resource(name="videoJson")  
  54.     private VideoJson videoJson;  
  55.       
  56.       
  57.     @Override    
  58.     public void execute(JobExecutionContext arg0) throws JobExecutionException {    
  59.         // TODO Auto-generated method stub    
  60.     }    
  61.         
  62.     public void executeA() throws JobExecutionException {    
  63.         // TODO Auto-generated method stub    
  64.         logger.info("==========clean redis videojson");  
  65.         //cleanRedis();  
  66.     }        
  67.       
  68.     /** 
  69.      * 每隔5分钟,执行一次 时间, 
  70.      * 在spring配置文件设置 dispatcher-servlet.xml 
  71.      */  
  72.     public void cleanRedis(){  
  73.            Pager pager = new Pager(12000);  
  74.            pager.setSortname("dateAdded");  
  75.            pager.setSortorder("desc");  
  76.            List list = m3u8ContentDAO.findList(pager);  
  77.            if(list.size()>0){  
  78.                for(int i=0;i
  79.                    M3u8Content m3u8content = new M3u8Content();  
  80.                    cleanRedisVideoJSon(m3u8content.getVideoPoolId());//覆盖redis.videojson缓存  
  81.                    logger.info("定时程序, 覆盖redis.videojson缓存");  
  82.                    //更改状态  
  83.                    m3u8content.setStatus(8);  
  84.                    m3u8ContentDAO.updateStatus(m3u8content);  
  85.                    logger.info("定时程序, 修改m3u8_content的status的值为8");  
  86.                }  
  87.            }  
  88.     }  
  89.       
  90.     /** 
  91.      * 定时清除videoJson 的redis缓存 
  92.      */  
  93.     public void cleanRedisVideoJSon(String vid){  
  94.             Jedis jedis = null;  
  95.             //String userid = vid.substring(0,10);  
  96.             //String jsonbody = JsonUtil.docToJson(vdoc);  
  97.             jedis = getPool().getResource();  
  98.             String videokey = "videojson_"+vid;  
  99.             //String userkey = "userjson_"+userid;  
  100.             String videojson = jedis.get(videokey);  
  101.             if(!StringUtil.isFine(videojson)){  
  102.                 DOC vdoc = videoJson.videoJson(vid);  
  103.                 if (vdoc!=null && vdoc.size()!=0){  
  104.                     videojson = JsonUtil.docToJson(vdoc);  
  105.                     //预防缓存了空json  
  106.                     if(videojson.length()>10){  
  107.                         jedis.set(videokey, videojson);  
  108.                     }  
  109.                 }  
  110.             }  
  111.     }  
  112.       
  113.       
  114.     /** 
  115.      * 测试方法 
  116.      */  
  117.     public void taskstart(){  
  118.         System.out.println("init");  
  119.         Pager pager = new Pager(11000);  
  120. //      pager.setSortname("dateAdded");  
  121. //      pager.setSortorder("desc");  
  122.           logger.info("================s==============");  
  123.           List list = m3u8ContentDAO.findList(pager);  
  124.           logger.info("==================s============"+list.size());  
  125.           logger.info("==================u============");  
  126.             
  127.           cleanRedisVideoJSon("fffdd2a8ecfdddfa9aee376070e1c759");//覆盖redis.videojson缓存  
  128.           M3u8Content m3u8content = new M3u8Content();  
  129.           m3u8content.setBitRateIndex(1);  
  130.           m3u8content.setVideoPoolId("fffdd2a8ecfdddfa9aee376070e1c759");  
  131.           m3u8content.setStatus(8);  
  132.           m3u8ContentDAO.updateStatus(m3u8content);  
  133.           logger.info("==================u============");  
  134.            logger.info("tomcat 测试方法");  
  135.     }  
  136.   
  137. }  

spring 定时任务调度设置:(在spring配置文件增加如下配置)

[html]  view plain  copy
  1.   
  2.     <bean id="initJob" class="com.cc.ovp.web.video.CleanVideoJsonRedis" />    
  3.              
  4.         
  5.     <bean id="initJobDetail"    
  6.         class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">    
  7.         <property name="targetObject" ref="initJob" />    
  8.         <property name="targetMethod" value="executeA" />    
  9.             
  10.     bean>    
  11.         
  12.     <bean id="initTrigger"      
  13.         class="org.springframework.scheduling.quartz.SimpleTriggerBean">      
  14.         <property name="jobDetail" ref="initJobDetail" />      
  15.         <property name="startDelay" value="10000" />    
  16.         <property name="repeatInterval" value="300000" />    
  17.           
  18.     bean>    
  19.         
  20.     <bean id="schedulerFactory"      
  21.         class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="no">      
  22.         <property name="triggers">      
  23.             <list>      
  24.                 <ref bean="initTrigger" />      
  25.             list>      
  26.         property>      
  27.         <property name="autoStartup" value="true"/>    
  28.     bean>    
  29.        
  30.   


并发执行设置

是设置执行模式的,大概意思是:比如您设置了5分钟,可以在该任务执行之后的5分钟后继续执行下一次,就是上一次任务必须执行完毕之后执行下一次。还有就是无论上次任务有没有执行完毕,那么过五分钟之后继续执行下次任务。

 

[html]  view plain  copy
  1.   
  2.     <bean id="initJob" class="com.cc.ovp.web.video.CleanVideoJsonRedis" />    
  3.              
  4.         
  5.     <bean id="initJobDetail"    
  6.         class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">    
  7.         <property name="targetObject" ref="initJob" />    
  8.         <property name="targetMethod" value="executeA" />  
  9.         <property name="concurrent" value="false" />    
  10.             
  11.     bean>    
  12.         
  13.     <bean id="initTrigger"      
  14.         class="org.springframework.scheduling.quartz.SimpleTriggerBean">      
  15.         <property name="jobDetail" ref="initJobDetail" />      
  16.         <property name="startDelay" value="10000" />    
  17.         <property name="repeatInterval" value="1000" />   
  18.     bean>    
  19.         
  20.     <bean id="schedulerFactory"      
  21.         class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="no">      
  22.         <property name="triggers">      
  23.             <list>      
  24.                 <ref bean="initTrigger" />      
  25.             list>      
  26.         property>      
  27.         <property name="autoStartup" value="true"/>    
  28.     bean>    
  29.        
  30.   

或者使用Java的线程池实现:

[java]  view plain  copy
  1. public void execute() throws InterruptedException {    
  2.     System.out.println("Start job");    
  3.     ExecutorService exec = Executors.newFixedThreadPool(1);    
  4.         
  5.     Thread thread = new Thread(new Runnable() {    
  6.         @Override    
  7.         public void run() {    
  8.             System.out.println("thread start");    
  9.             try {    
  10.                 Thread.sleep(3000);    
  11.             } catch (InterruptedException e) {    
  12.                 // TODO Auto-generated catch block    
  13.                 e.printStackTrace();    
  14.             }    
  15.             System.out.println("thread end");    
  16.         }    
  17.     });    
  18.     exec.execute(thread);    
  19.     exec.shutdown();    
  20.        while (!exec.isTerminated()) {    
  21.            // 等待所有子线程结束,才退出主线程    
  22.        }            
  23.     System.out.println("end job");    
  24. }   

OK,至此spring quartz多线程并发问题解决。回顾下,我们要使用isTerminated()方法等多线程结束后在结束job;多线程任务派发结束后,要使用shutdown()方法顺序关闭线程(等待正在执行任务,不接受新任务)

你可能感兴趣的:(Tomcat相关)