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()),启动另一个线程来执行,具体代码如下。
package com.bijian.web.video; import static com.bijian.util.RedisUtils.getPool; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; import javax.annotation.Resource; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import redis.clients.jedis.Jedis; import ayou.util.DOC; import ayou.util.StringUtil; import com.cc.ovp.dao.M3u8ContentDAO; import com.cc.ovp.dao.M3u8_db; import com.cc.ovp.domain.M3u8Content; import com.cc.ovp.service.MongoSearchService; import com.cc.ovp.util.JsonUtil; import com.cc.ovp.util.Pager; /** * 定时清理一下videojson 的redis缓存 * 需求: * 查询m3u8_content的status字段不为8, * 就清除redis 缓存,重新set值到redis, * cleanRedisVideoJSon(String vid), * 更新m3u8_content的status 字段为8 */ @Controller public class CleanVideoJsonRedis extends HttpServlet{ private static final Logger logger = LoggerFactory.getLogger(CleanVideoJsonRedis.class); private final int sleepTime=5*60*1000; @Resource(name = "m3u8ContentDAO") private M3u8ContentDAO m3u8ContentDAO; @Resource(name="videoJson") private VideoJson videoJson; // Servlet的init方法会在Tomcat启动的时候执行 @Override public void init() throws ServletException { FutureTask<String> task = new FutureTask<String>(new Callable<String>(){ @Override public String call() throws Exception { taskstart(); //使用另一个线程来执行该方法,会避免占用Tomcat的启动时间 return "Collection Completed"; } }); new Thread(task).start();; } public void taskstart(){ while (true) { try { System.out.println("init"); System.out.println("=============================="); Thread.sleep(5*1000); Pager pager = new Pager(1, 200); pager.setSortname("dateAdded"); pager.setSortorder("desc"); List<M3u8Content> list = m3u8ContentDAO.findList(pager); System.out.println("=============================="+list.size()); logger.info("tomcat 测试方法"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
web.xml配置文件增加一个serlvet。
<servlet> <servlet-name>event-collector</servlet-name> <servlet-class>com.bijian.web.video.CleanVideoJsonRedis</servlet-class> <load-on-startup>60</load-on-startup> </servlet> <servlet-mapping> <servlet-name>event-collector</servlet-name> <url-pattern>/event-collect</url-pattern> </servlet-mapping>
方法二:
配置一个Listener来启动。
web.xml
<!-- Spring 上下文监听器 由此启动Spring上下文容器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 增加监听启动类的listener --> <listener> <listener-class>com.bijian.web.video.CleanVideoJsonRedis</listener-class> </listener>
注意:<listener/> 标签一定要在<filter/>之后,在<servlet/>之前配置。
CleanVideoJsonRedis.java
package com.baijian.web.video; import javax.servlet.*; import java.util.*; public class CleanVideoJsonRedis implements ServletContextListener{ public CleanVideoJsonRedis(){ System.out.println("调用了构造方法"); } public void contextInitialized(ServletContextEvent event) { System.out.println(" ----------创建了Context created on " + new Date() + "."); } public void contextDestroyed(ServletContextEvent event) { System.out.println("--------销毁了Context destroyed on " + new Date() + "."); } }
说明:listener 配置在web.xml中,当web服务启动时,会实例化<listener-class/>中指定的类,所以里面一定要写完整类路径。
方法三:
使用Spring的Timer或者是著名的Quartz在Tomcat启动后再执行该方法,Spring中的Timer非常简单,这个地方不想讲解了,Quartz相对更复杂些,下面主要介绍下在Spring中怎么样使用Quartz来实现上面的需求。
例子:
package com.bijian.web.video; import static com.cc.ovp.util.RedisUtils.getPool; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; import javax.annotation.Resource; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import redis.clients.jedis.Jedis; import ayou.util.DOC; import ayou.util.StringUtil; import com.cc.ovp.dao.M3u8ContentDAO; import com.cc.ovp.dao.M3u8_db; import com.cc.ovp.domain.M3u8Content; import com.cc.ovp.service.MongoSearchService; import com.cc.ovp.util.JsonUtil; import com.cc.ovp.util.Pager; /** * 定时清理一下videojson 的redis缓存 * 需求: * 查询m3u8_content的status字段不为8, * 就清除redis 缓存,重新set值到redis, * cleanRedisVideoJSon(String vid), * 更新m3u8_content的status 字段为8 */ @Controller public class CleanVideoJsonRedis implements Job{ private static final Logger logger = LoggerFactory.getLogger(CleanVideoJsonRedis.class); private final int sleepTime=5*60*1000; @Resource(name = "m3u8ContentDAO") private M3u8ContentDAO m3u8ContentDAO; @Resource(name="videoJson") private VideoJson videoJson; @Override public void execute(JobExecutionContext arg0) throws JobExecutionException { // TODO Auto-generated method stub } public void executeA() throws JobExecutionException { // TODO Auto-generated method stub logger.info("==========clean redis videojson"); //cleanRedis(); } /** * 每隔5分钟,执行一次 时间, * 在spring配置文件设置 dispatcher-servlet.xml */ public void cleanRedis(){ Pager pager = new Pager(1, 2000); pager.setSortname("dateAdded"); pager.setSortorder("desc"); List<M3u8Content> list = m3u8ContentDAO.findList(pager); if(list.size()>0){ for(int i=0;i<list.size();i++){ M3u8Content m3u8content = new M3u8Content(); cleanRedisVideoJSon(m3u8content.getVideoPoolId());//覆盖redis.videojson缓存 logger.info("定时程序, 覆盖redis.videojson缓存"); //更改状态 m3u8content.setStatus(8); m3u8ContentDAO.updateStatus(m3u8content); logger.info("定时程序, 修改m3u8_content的status的值为8"); } } } /** * 定时清除videoJson 的redis缓存 */ public void cleanRedisVideoJSon(String vid){ Jedis jedis = null; //String userid = vid.substring(0,10); //String jsonbody = JsonUtil.docToJson(vdoc); jedis = getPool().getResource(); String videokey = "videojson_"+vid; //String userkey = "userjson_"+userid; String videojson = jedis.get(videokey); if(!StringUtil.isFine(videojson)){ DOC vdoc = videoJson.videoJson(vid); if (vdoc!=null && vdoc.size()!=0){ videojson = JsonUtil.docToJson(vdoc); //预防缓存了空json if(videojson.length()>10){ jedis.set(videokey, videojson); } } } } /** * 测试方法 */ public void taskstart(){ System.out.println("init"); Pager pager = new Pager(1, 1000); // pager.setSortname("dateAdded"); // pager.setSortorder("desc"); logger.info("================s=============="); List<M3u8Content> list = m3u8ContentDAO.findList(pager); logger.info("==================s============"+list.size()); logger.info("==================u============"); cleanRedisVideoJSon("fffdd2a8ecfdddfa9aee376070e1c759");//覆盖redis.videojson缓存 M3u8Content m3u8content = new M3u8Content(); m3u8content.setBitRateIndex(1); m3u8content.setVideoPoolId("fffdd2a8ecfdddfa9aee376070e1c759"); m3u8content.setStatus(8); m3u8ContentDAO.updateStatus(m3u8content); logger.info("==================u============"); logger.info("tomcat 测试方法"); } }
spring 定时任务调度设置:(在spring配置文件增加如下配置)
<!-- 配置 定时任务 videoJson.redisbegin Begin --> <bean id="initJob" class="com.bijian.web.video.CleanVideoJsonRedis" /> <!--定时器任务配置(开始)--> <!--配置JOB--> <bean id="initJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="initJob" /> <property name="targetMethod" value="executeA" /> <!-- <property name="arguments" /> --> </bean> <!--配置Trigger--> <bean id="initTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="initJobDetail" /> <property name="startDelay" value="10000" /> <property name="repeatInterval" value="300000" /> <!-- <property name="repeatCount" value="0" /> --> </bean> <!--配置Scheduler--> <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="no"> <property name="triggers"> <list> <ref bean="initTrigger" /> </list> </property> <property name="autoStartup" value="true"/> </bean> <!--定时器任务配置(结束)--> <!-- 配置 定时任务 videoJson.redisbegin end -->
并发执行设置
是设置执行模式的,大概意思是:比如您设置了5分钟,可以在该任务执行之后的5分钟后继续执行下一次,就是上一次任务必须执行完毕之后执行下一次。还有就是无论上次任务有没有执行完毕,那么过五分钟之后继续执行下次任务。<property name="concurrent" value="false" />
<!-- 配置 定时任务 videoJson.redisbegin Begin --> <bean id="initJob" class="com.bijian.web.video.CleanVideoJsonRedis" /> <!--定时器任务配置(开始)--> <!--配置JOB--> <bean id="initJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="initJob" /> <property name="targetMethod" value="executeA" /> <property name="concurrent" value="false" /> <!-- 不允许并发 --> <!-- <property name="arguments" /> --> </bean> <!--配置Trigger--> <bean id="initTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="initJobDetail" /> <property name="startDelay" value="10000" /> <property name="repeatInterval" value="1000" /> </bean> <!--配置Scheduler--> <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="no"> <property name="triggers"> <list> <ref bean="initTrigger" /> </list> </property> <property name="autoStartup" value="true"/> </bean> <!--定时器任务配置(结束)--> <!-- 配置 定时任务 videoJson.redisbegin end -->
或者使用Java的线程池实现:
public void execute() throws InterruptedException { System.out.println("Start job"); ExecutorService exec = Executors.newFixedThreadPool(1); Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("thread start"); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("thread end"); } }); exec.execute(thread); exec.shutdown(); while (!exec.isTerminated()) { // 等待所有子线程结束,才退出主线程 } System.out.println("end job"); }
至此spring quartz多线程并发问题解决。回顾下,我们要使用isTerminated()方法等多线程结束后再结束job;多线程任务派发结束后,要使用shutdown()方法顺序关闭线程(等待正在执行任务,不接受新任务)。
相关推荐
- **利用 Job 完成后停止调度器**:可以在 Job 中实现逻辑,在任务执行完毕后关闭调度器。这种方式需要更细致地控制 Job 的生命周期。 ```java public void execute(JobExecutionContext context) throws ...
总的来说,配置Eclipse与Tomcat 7的集成是一项基础且重要的任务,对于Java Web开发者来说必不可少。通过上述步骤,开发者能够快速地在Eclipse环境中建立开发环境,为后续的Web应用开发打下坚实的基础。随着对Eclipse...
6. 任务执行完毕后,线程返回到线程池,重新标记为空闲,等待下次分配。 Tomcat的线程池设计注重平衡资源利用率和响应速度。通过控制线程的创建和销毁,避免频繁的线程创建销毁带来的性能开销。同时,`ThreadPool`...
在 Windows 环境下配置 Nginx 作为 Tomcat 的反向代理服务器是一项常见的任务,主要用于实现负载均衡、提高安全性及提升性能等目的。本文将从下载 Nginx 开始,详细介绍如何在 Windows 系统上完成这一配置。 #### ...
Linux环境下安装配置Tomcat是一个常见的任务,特别是在需要运行基于Java的Web应用程序时。Tomcat作为Apache软件基金会Jakarta项目的组成部分,是一个开源且免费的Web应用服务器,特别适合于中小型系统和并发访问用户...
将查询结果在新的SQL窗口中执行,执行完毕后重新启动服务。 此外,如果遇到EOS连接失败的问题,可以查看是否有被锁的对象。使用以下查询查看所有被锁对象: ```sql select * from v$locked_object; ``` 进一步确定...
配置完毕后,可以通过启动Tomcat的`startup.sh`脚本来启动服务,使用`shutdown.sh`脚本来停止服务。在浏览器中输入`http://localhost:8080`,如果能看到Tomcat的欢迎页面,说明Tomcat已经成功运行。 最后,配置...
在Redhat LINUX5.0操作系统上安装Oracle 10g、Tomcat5和JDK是一项技术性较强的任务,涉及到多个层面的知识点。首先,我们来详细解析这些关键组件的安装和配置过程。 1. **Oracle 10g安装**: Oracle 10g是一款关系...
安装完成后,任务栏右下角会出现Tomcat的服务图标。若未启动,图标显示为红色。启动Tomcat服务,可以通过右键点击图标,选择"Start Service"。启动后,图标变为绿色三角形。同样,你可以通过"Stop Service"来停止...
2. **初始化生命周期监听器**:根据配置,初始化一系列监听器,用于在特定生命周期事件(如启动、停止等)中执行特定任务。 3. **启动Connector**:Coyote组件负责监听网络端口,接收HTTP请求。 4. **启动Engine**:...
在Linux系统中安装Apache Tomcat 7.0.82是一个常见的任务,尤其对于那些需要部署Java Web应用程序的开发者来说。下面将详细介绍如何在Linux环境下简单有效地安装Tomcat 7.0.82。 首先,我们需要获取Apache Tomcat的...
完成上述步骤后,Apache2.2和Tomcat6就已经整合完毕,可以通过Apache访问部署在Tomcat上的Java Web应用程序了。注意,在实际操作中可能需要根据具体的系统环境和需求进行调整,例如端口设置、防火墙规则等。
解压完毕后,需要进入Tomcat的bin目录找到service.bat文件,并对其进行编辑。通常编辑操作需要打开命令提示符cmd(如果权限不足,以管理员身份运行)。 在service.bat中,可以通过搜索"setSERVICE_NAME="来设置服务...
在Windows 10操作系统中,安装和部署Apache Tomcat服务器是一项基本的任务,这对于开发者和运维人员来说至关重要。本文将详细讲解这一过程,分为两个主要部分:Java环境的配置和Tomcat的安装与部署。 首先,Java...
Solr,全称为Apache Solr,是一款开源的全文搜索引擎,被广泛应用于企业级...一旦配置完毕,通过Tomcat启动Solr,便可以开始进行高效的全文搜索了。这个预配置的环境为你提供了快速上手的基础,大大简化了部署流程。
修改完毕后重启Tomcat服务器,乱码问题应该会被解决。 其次,关于Tomcat端口占用的问题,这通常发生在服务器尝试绑定到一个已经被其他进程使用的端口上。在Windows系统中,可使用命令行工具netstat -ano来查看哪个...
解压完毕后,接下来就是启动Tomcat服务器。在Tomcat的bin目录里双击运行startup.bat文件,如果成功启动,浏览器输入地址“***.*.*.*:8080”或“localhost:8080”便可以访问Tomcat的主界面。 在使用Tomcat过程中,...
首先,我们需要在`web.xml`中将JobExecutorServlet的配置暂时注释掉,防止它在Tomcat启动时自动加载。以下是相关的XML配置段: ```xml <!-- <servlet-name>JobExecutorServlet <servlet-class>org.jbpm.job....