文档章节

解决Spring定时计划任务重复执行两次(实例被构造两次)问题的方法

嘻哈开发者
 嘻哈开发者
发布于 2015/08/23 18:12
字数 2071
阅读 915
收藏 11
点赞 0
评论 0

今天在做一个项目的时候用到了Spring的定时计划任务。这是Spring的特色功能,可以根据设置在特定的时间或间隔时间做特定的事。

下面给出一个例子:

[java]  view plain copy
  1. package net.csdn.blog.chaijunkukn;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.Calendar;  
  5. import java.util.Locale;  
  6.   
  7. public class TimerTask {  
  8.     public void printTimeStamp(){  
  9.         Calendar ca= Calendar.getInstance();  
  10.         ca.setTimeInMillis(System.currentTimeMillis());  
  11.         SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ", Locale.CHINA);  
  12.         //显示当前时间 精确到毫秒  
  13.         System.out.print(sdf.format(ca.getTime()));       
  14.     }  
  15.     public TimerTask(){  
  16.         this.printTimeStamp();  
  17.         System.out.println("计划任务被初始化了");  
  18.     }  
  19.     public void doTask(){  
  20.         this.printTimeStamp();        
  21.         System.out.print("计划任务被执行,线程id:");  
  22.         System.out.println(Thread.currentThread().getId());  
  23.     }  
  24. }  


根据Spring关于定时任务的规范,任务执行方法应为无参数无返回的方法,因此按照规范上面的例子中声明了doTask方法。上面的例子很简单,Spring作为IoC容器,构造TimerTask实例时会调用无参构造函数,此类会在实例化时在控制台输出当前时间和构造信息。当定时任务被触发时,也会在控制台显示当前时间和任务被执行的提示信息。

下面是配置(需要声明的是,本实例基于J2EE工程,使用了log4j,配置文件只是工程中的一部分): 

[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5.        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  
  6.     <!-- 注册定时器 -->  
  7.     <bean id="timer"  
  8.         class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
  9.         <property name="triggers">  
  10.             <list>  
  11.                 <ref bean="timerTaskTrigger" />  
  12.             </list>  
  13.         </property>  
  14.     </bean>  
  15.     <!-- 指定何时触发定时任务 -->  
  16.     <bean id="timerTaskTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">  
  17.         <property name="jobDetail">  
  18.             <ref bean="timerTaskJobDetail" />  
  19.         </property>  
  20.         <property name="cronExpression">  
  21.             <!-- 每3秒钟触发一次 -->  
  22.             <value>0/3 * * * * ?</value>  
  23.         </property>  
  24.     </bean>  
  25.     <!-- 指定定时任务细节 调用哪个类 哪个方法 -->  
  26.     <bean id="timerTaskJobDetail"  
  27.         class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
  28.         <property name="targetObject">  
  29.             <ref bean="timerTaskInstance" />  
  30.         </property>  
  31.         <property name="targetMethod">  
  32.             <value>doTask</value>  
  33.         </property>  
  34.         <property name="concurrent" value="false" />  
  35.     </bean>  
  36.     <!-- 实例化定时任务类 -->  
  37.     <bean id="timerTaskInstance" class="net.csdn.blog.chaijunkukn.TimerTask" />  
  38. </beans>  

 

web.xml的配置: 

[html]  view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app id="WebApp_ID" version="2.4"  
  3.     xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
  5.     <display-name>TaskTest</display-name>  
  6.     <servlet>  
  7.         <servlet-name>springapp</servlet-name>  
  8.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  9.         <init-param>  
  10.             <param-name>contextConfigLocation</param-name>  
  11.             <param-value>/WEB-INF/classes/applicationContext*.xml</param-value>  
  12.         </init-param>  
  13.         <load-on-startup>1</load-on-startup>  
  14.     </servlet>  
  15.   
  16.     <servlet-mapping>  
  17.         <servlet-name>springapp</servlet-name>  
  18.         <url-pattern>*.htm</url-pattern>  
  19.     </servlet-mapping>  
  20.   
  21.     <filter>  
  22.         <filter-name>EncodingFilter</filter-name>  
  23.         <filter-class>com.ku6.tech.wap.filter.EncodingFilter</filter-class>  
  24.         <init-param>  
  25.             <param-name>encoding</param-name>  
  26.             <param-value>utf-8</param-value>  
  27.         </init-param>  
  28.         <init-param>  
  29.             <param-name>forceEncoding</param-name>  
  30.             <param-value>true</param-value>  
  31.         </init-param>  
  32.     </filter>  
  33.       
  34.     <filter-mapping>  
  35.         <filter-name>EncodingFilter</filter-name>  
  36.         <url-pattern>*.htm</url-pattern>  
  37.     </filter-mapping>  
  38.   
  39.     <error-page>  
  40.         <error-code>404</error-code>  
  41.         <location>/error.jsp</location>  
  42.     </error-page>  
  43.   
  44.     <welcome-file-list>  
  45.         <welcome-file>index.jsp</welcome-file>  
  46.     </welcome-file-list>  
  47.   
  48.     <listener>  
  49.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  50.     </listener>  
  51.   
  52.     <context-param>  
  53.         <param-name>contextConfigLocation</param-name>  
  54.         <param-value>/WEB-INF/classes/applicationContext*.xml</param-value>  
  55.     </context-param>  
  56. </web-app>  

 

配置的部分就是这样,然后我使用MyEclipse 9.1关联上Tomcat服务器。一切都是默认的设置,然后将本引用部署并启动Tomcat服务器。

这时候问题来了,我的任务类居然被创建了两次,下面是截取的部分日志数据:

[html]  view plain copy
  1. 2011-11-01 19:09:02,568 INFO [main] - org.springframework.orm.hibernate3.HibernateTransactionManager.afterPropertiesSet(421) | Using DataSource [org.apache.commons.dbcp.BasicDataSource@f2ff9b] of Hibernate SessionFactory for HibernateTransactionManager  
  2. 2011-11-01 19:09:02,756 INFO [main] - org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer.postProcessTemplateLoaders(124) | ClassTemplateLoader for Spring macros added to FreeMarker configuration  
  3. 2011-11-01 19:09:03.878 计划任务被初始化了  
  4. 2011-11-01 19:09:03,987 INFO [main] - org.quartz.core.SchedulerSignalerImpl.<init>(63) | Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl  
  5. 2011-11-01 19:09:03,987 INFO [main] - org.quartz.core.QuartzScheduler.<init>(214) | Quartz Scheduler v.1.6.1-RC1 created.  
  6. ...  
  7. 2011-11-01 19:09:05,140 WARN [main] - org.hibernate.cache.EhCacheProvider.buildCache(86) | Could not find configuration [org.hibernate.cache.StandardQueryCache]; using defaults.  
  8. 2011-11-01 19:09:05,218 INFO [main] - org.springframework.orm.hibernate3.HibernateTransactionManager.afterPropertiesSet(421) | Using DataSource [org.apache.commons.dbcp.BasicDataSource@85b4c5] of Hibernate SessionFactory for HibernateTransactionManager  
  9. 2011-11-01 19:09:05,218 INFO [main] - org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer.postProcessTemplateLoaders(124) | ClassTemplateLoader for Spring macros added to FreeMarker configuration  
  10. 2011-11-01 19:09:05.249 计划任务被初始化了  
  11. 2011-11-01 19:09:05,249 INFO [main] - org.quartz.core.SchedulerSignalerImpl.<init>(63) | Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl  
  12. 2011-11-01 19:09:05,249 INFO [main] - org.quartz.core.QuartzScheduler.<init>(214) | Quartz Scheduler v.1.6.1-RC1 created.  
  13. ...  
  14. 2011-11-1 19:09:05 org.apache.catalina.startup.Catalina start  
  15. 信息: Server startup in 9451 ms  
  16. 2011-11-01 19:09:06.013 计划任务被执行,线程id:17  
  17. 2011-11-01 19:09:06.013 计划任务被执行,线程id:39  
  18. 2011-11-01 19:09:09.021 计划任务被执行,线程id:19  
  19. 2011-11-01 19:09:09.021 计划任务被执行,线程id:40  


从上面的日志中可以看出,

在2011-11-01 19:09:03.878 定时计划任务类产生了一个实例 

在2011-11-01 19:09:05.249 定时 计划任务类又产生了一个实例

起初我对它并不关心,但是下面的问题却是不可接受的,计划任务确实是差不多每隔3秒钟被调度的,但是每次调度执行了任务方法两次。设想一下,这仅仅是个开销很小的例子,但是如果这个方法执行的是一个非常耗时耗资源的任务,好不容易执行完一次后又要执行一次,这是对计算资源的极大浪费。于是查找了一天的原因,最后在国外的一个论坛上找到了解决的办法(http://forum.springsource.org/showthread.php?33311-IoC-Container-initializes-my-app-twice)。

 

楼主roncox和我遇到了同样的问题,他和我的配置差不多,同样也贴出了配置文件。虽然其他人没有解决问题,但是他自己解决了,并提供了最后的解决方法:

 

解决办法就是将web.xml配置文件中的如下节点删掉:

[html]  view plain copy
  1. <listener>  
  2.     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  3. </listener>  
  4.   
  5. <context-param>  
  6.     <param-name>contextConfigLocation</param-name>  
  7.     <param-value>/WEB-INF/classes/applicationContext*.xml</param-value>  
  8. </context-param>  


修改之后程序运行一切正常。个人推测,由于org.springframework.web.context.ContextLoaderListener和org.springframework.web.servlet.DispatcherServlet都能够加载applicationContext*.xml(“*”是通配符,表示所有以“applicationContext”开头的xml文件)。而两个类殊途同归,最终都将这些配置文件交给了Spring框架的Ioc容器进行实例化。因此每个类都会被实例化两次。


2012年1月10日补充:今天做项目自习研究了一下spring的配置文件,发现之前说的不完全正确,不应该删除web.xml中的如下节点

[html]  view plain copy
  1. <listener>  
  2.     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  3. </listener>  
  4.   
  5. <context-param>  
  6.     <param-name>contextConfigLocation</param-name>  
  7.     <param-value>/WEB-INF/classes/applicationContext*.xml</param-value>  
  8. </context-param>  

因为该节点指派的applicationContext*.xml是用于实例化除servlet之外的所有对象的,可以说项目中绝大多数的service和dao层操作都由ContextLoaderListener传递给Spring来进行实例化。

在web应用中,web.xml还经常出现如下的配置:

[html]  view plain copy
  1. <!--全局Servlet调度配置 -->  
  2.     <servlet>  
  3.         <!--若设置 servlet-name为[name] -->  
  4.         <!--则DispatcherServlet在实例化后会自动加载[name]-servlet.xml -->  
  5.         <servlet-name>spring</servlet-name>  
  6.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  7.         <init-param>  
  8.             <param-name>contextConfigLocation</param-name>  
  9.             <param-value>classpath:servletContext.xml</param-value>  
  10.         </init-param>  
  11.         <!--随服务器一同启动 -->  
  12.         <load-on-startup>1</load-on-startup>  
  13.     </servlet>  
  14.     <servlet-mapping>  
  15.         <servlet-name>spring</servlet-name>  
  16.         <url-pattern>*.do</url-pattern>  
  17.     </servlet-mapping>  
这个是用来处理所有servlet的,没有它就无法通过请求地址来调用相应的Controller。
这里我明确地指示了要加载类路径下的servletContext.xml,如果不指定,则会按照注释中所描述地那样自动加载spring-servlet.xml
无论是servletContext.xml还是applicationContext*.xml都可以按照<beans>...<bean id="XXX" class="XXX" />...</beans>这样的形式来配置。
问题来了,有时候不注重对象初始化的分类,尤其是使用<context:component-scan base-package="controller" />这样的包扫描形式统一初始化,
很容易造成满足条件的对象被初始化两次,那么在计划任务的时候被执行两次也就不奇怪了。其实说来说去,还是要提醒大家,不同的配置文件其作用是不一样的,
不要将所有的初始化操作都放到一个配置文件中,更不要重复配置。不仅浪费资源,还很容易导致莫名其妙的故障。

 

另外,有相关文章还提到过是Tomcat服务器的问题,修改conf目录下的server.xml。修改节点Host,将appBase属性由默认的“webapps”设置为空("")即可,如下所示:

[html]  view plain copy
  1. <Host name="localhost" appBase="" unpackWARs="true" autoDeploy="true"  
  2.     xmlValidation="false" xmlNamespaceAware="false">  
  3.   
  4.     <Context docBase="/usr/local/apache-tomcat-6.0.29/webapps/semwinner"  
  5.         path="" reloadable="true"></Context>  
  6.     <Context docBase="/usr/local/apache-tomcat-6.0.29/webapps/emarboxmanager"  
  7.         path="/admin" reloadable="true"></Context>  
  8. </Host>    

但是本人尝试之后并没有起作用。可能不适用于我遇到的这个问题。写出上面解决方法的作者认为web应用程序默认都是放在webapps这个目录下的,如果不把“webapps“去掉,这里会调用一次quartz的任务调度,在接下来的“<Context path”中又会调用一次quartz的任务调度,所以就重复了2次。两个方法都写出来,供朋友们参考。

第二种解决方法来自http://nkliuliu.iteye.com/blog/816335

本文转载自:http://blog.csdn.net/chaijunkun/article/details/6925889

共有 人打赏支持
嘻哈开发者
粉丝 54
博文 113
码字总数 1519
作品 0
广州
程序员
Spring 定时任务重复执行的问题分析

Spring 定时任务重复执行的问题分析 背景:使用quartz时客户现场不知道为什么跑着跑着就停了,后来决定换成spring定时任务。 当使用spring定时任务时莫名奇妙的就是同一时间重复执行多次任务...

huxy534 ⋅ 2017/05/11 ⋅ 0

基于RAMJobStore开发出现的几个问题

1.更新任务 先前我们在更新任务时,虽然更新了定时任务的执行时间,但是并没有对参数进行更新,即使用context.getMergedJobDataMap().get(...)方法获取到的参数还是旧的。 假设我们更新了任务...

tmac1yan ⋅ 2016/01/21 ⋅ 0

关于Spring中用quartz定时器在定时到达时同时执行两次的问题

我在使用spring的quartz配置定时任务时,发现每次定时时间到达后,指定的定时方法同时执行两次,而且此方法还是使用的synchronized关键字,每次定时一到,会发现此方法内的System.out输出信息输出...

迷途d书童 ⋅ 2012/03/09 ⋅ 1

springmvc初始化数据

在使用springmvc时,我们也会在项目启动时初始化一些数据,具体的方式见下面的链接。 这里我只贴一下InitializingBean的例子。 注意事项: springmvc和sping整合时,配置注解的注意事项! 不注意...

韩立伟 ⋅ 2017/12/07 ⋅ 0

解决Quartz定时任务被触发两次的问题(附带:Quartz的测试用例)

很多人在使用spring的Quartz配置定时任务时,会发现每次定时时间到达后,指定的定时方法同时执行了两次。 (P.S. 本人项目用的Jfinal搭建,同样出现该问题。) 解决quartz定时任务被触发两次的...

EugeneQiu ⋅ 2014/05/15 ⋅ 17

Spring 监听器定义两个定时器在同一时间重复执行两次,实际上Spring监听器ApplicationListener执行了3遍

Spring+hibernate定义两个定时器在同一时间重复执行两次,是因为使用了两个定时器导致线程紊乱了吗?在Web程序启动的时候会同时执行两个定时器 public void onApplicationEvent(ContextRefr...

bubblehead ⋅ 2016/10/21 ⋅ 3

Java Web定时任务这一篇就够了

一、Java定时任务 1、Timer 包下面一个工具类,从1.3开始便支持了; 说明下后两个参数分别是delay延迟执行,和period执行间隔,单位都是毫秒。 2、ScheduledExecutorService 包下面,从1.5开...

叫我宫城大人 ⋅ 04/16 ⋅ 0

springMVC面试题二

一、spring是一个开源的J2EE框架,而且开发快捷,耦合度相对来说比较低,方便后续的修改,而且一直持续更新,和别的一些orm框架以及其他框架能够很好地结合使用,所以用的比较多。 二、sprin...

四月李 ⋅ 2015/12/20 ⋅ 0

Spring @Scheduled 在tomcat容器里面执行两次

今天在用spring里面的@Scheduled执行定时任务,但是发现到触发定时任务的时间点总会执行两次。开始一直以为是spring配置出了问题。后面换了一台主机,在里面的tomcat跑了程序,只执行了一次。...

_桃子_ ⋅ 2015/11/27 ⋅ 0

Spring task配置,及解决加载两次的方法

关于 启动Task任务同时加载两次的解决方法: 将spring MVC部分的定义另外建立一个文件,同时把Task配置放在此处,然后在web.xml文件中的处加载 <servlet><servlet-name>SpringMVC</servlet-...

夏碌冬藏 ⋅ 2014/08/04 ⋅ 2

没有更多内容

加载失败,请刷新页面

加载更多

下一页

jsonrpc-4j代码解析

解析文件 AutoJsonRpcServiceImplExporter JsonServiceExporter AutoJsonRpcServiceImplExporter 路径:com.googlecode.jsonrpc4j.spring.AutoJsonRpcServiceImplExporter AutoJsonRpcServi......

郭恩洲_OSC博客 ⋅ 41分钟前 ⋅ 0

百度搜索

from selenium import webdriver import time brower=webdriver.Firefox() brower.get('http://www.baidu.com') input=brower.find_element_by_id('kw') input.send_keys('中南大学') time.s......

南桥北木 ⋅ 48分钟前 ⋅ 0

tomcat 日志记录器

1、日志记录器是记录消息的组件 日志记录器需要与某个servlet 容器相关联 2、Logger 接口 共定义了5种日志级别:FATAL、ERROR、WARNING、INFORMATION、DEBUGGER setVerbosity 设置级别 setC...

职业搬砖20年 ⋅ 49分钟前 ⋅ 0

Thrift RPC实战(三) Thrift序列化机制

1.Thrift基础架构 Thrift是一个客户端和服务端的架构体系,数据通过socket传输; 具有自己内部定义的传输协议规范(TProtocol)和传输数据标准(TTransports); 通过IDL脚本对传输数据的数据结构...

lemonLove ⋅ 49分钟前 ⋅ 0

网站建设就要像2018世界杯的俄罗斯队大杀四方[图]

今天心情不错,因为昨天晚上观看了世界杯比赛,尤其是对俄罗斯队的大杀四方感到十分霸气侧漏啊,因此我联想到了自己的博客网站,我的博客是去年年底上线的,一直想建设一个关于读书和读后感作...

原创小博客 ⋅ 58分钟前 ⋅ 0

Greenplum 三节点安装教程(非root用户)

Greenplum 三节点安装教程(非root用户) 环境准备 安装vmware,装三台centos 虚拟机设置: 主机名 IP 内存 硬盘 node1 Xxx1 2G 80G node2 Xxx2 2G 80G node3 Xxx3 2G 80G CSDN下载greenplum...

仔仔1993 ⋅ 59分钟前 ⋅ 0

linux 信号机制

signal(SIGPIPE, SIG_IGN); TCP是全双工的信道, 可以看作两条单工信道, TCP连接两端的两个端点各负责一条. 当对端调用close时, 虽然本意是关闭整个两条信道, 但本端只是收到FIN包. 按照TCP协...

xxdd ⋅ 今天 ⋅ 0

SpringWind

环境搭建和系统部署

颖伙虫 ⋅ 今天 ⋅ 0

vim命令用法

第五章 vim命令 vim和vi几乎是一样的,唯一的区别就是当编辑一个文本时,使用vi不会显示颜色,而使用vim会显示颜色。 vim有三个模式:一般模式,编辑模式,命令模式。 系统最小化安装时没有安...

弓正 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部