- 浏览: 1054139 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (1441)
- 软件思想&演讲 (9)
- 行业常识 (250)
- 时时疑问 (5)
- java/guava/python/php/ruby/R/scala/groovy (213)
- struct/spring/springmvc (37)
- mybatis/hibernate/JPA (10)
- mysql/oracle/sqlserver/db2/mongdb/redis/neo4j/GreenPlum/Teradata/hsqldb/Derby/sakila (268)
- js/jquery/jqueryUi/jqueryEaseyUI/extjs/angulrJs/react/es6/grunt/zepto/raphael (81)
- ZMQ/RabbitMQ/ActiveMQ/JMS/kafka (17)
- lucene/solr/nuth/elasticsearch/MG4J (167)
- html/css/ionic/nodejs/bootstrap (19)
- Linux/shell/centos (56)
- cvs/svn/git/sourceTree/gradle/ant/maven/mantis/docker/Kubernetes (26)
- sonatype nexus (1)
- tomcat/jetty/netty/jboss (9)
- 工具 (17)
- ETL/SPASS/MATLAB/RapidMiner/weka/kettle/DataX/Kylin (11)
- hadoop/spark/Hbase/Hive/pig/Zookeeper/HAWQ/cloudera/Impala/Oozie (190)
- ios/swift/android (9)
- 机器学习&算法&大数据 (18)
- Mesos是Apache下的开源分布式资源管理框架 (1)
- echarts/d3/highCharts/tableau (1)
- 行业技能图谱 (1)
- 大数据可视化 (2)
- tornado/ansible/twisted (2)
- Nagios/Cacti/Zabbix (0)
- eclipse/intellijIDEA/webstorm (5)
- cvs/svn/git/sourceTree/gradle/jira/bitbucket (4)
- jsp/jsf/flex/ZKoss (0)
- 测试技术 (2)
- splunk/flunm (2)
- 高并发/大数据量 (1)
- freemarker/vector/thymeleaf (1)
- docker/Kubernetes (2)
- dubbo/ESB/dubboX/wso2 (2)
最新评论
今天在做一个项目的时候用到了Spring的定时计划任务。这是Spring的特色功能,可以根据设置在特定的时间或间隔时间做特定的事。
下面给出一个例子:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
01.package net.csdn.blog.chaijunkukn;
02.
03.import java.text.SimpleDateFormat;
04.import java.util.Calendar;
05.import java.util.Locale;
06.
07.public class TimerTask {
08. public void printTimeStamp(){
09. 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,配置文件只是工程中的一部分):
[java] view plaincopy在CODE上查看代码片派生到我的代码片
01.<?xml version="1.0" encoding="utf-8"?>
02.<beans xmlns="http://www.springframework.org/schema/beans"
03. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04. xsi:schemaLocation="http://www.springframework.org/schema/beans
05. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
06. <!-- 注册定时器 -->
07. <bean id="timer"
08. class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
09. <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的配置:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
01.<?xml version="1.0" encoding="UTF-8"?>
02.<web-app id="WebApp_ID" version="2.4"
03. xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04. xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
05. <display-name>TaskTest</display-name>
06. <servlet>
07. <servlet-name>springapp</servlet-name>
08. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
09. <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>
•load-on-startup标记容器是否在启动的时候实例化并调用其init()方法的优先级。
•它的值表示servlet应该被载入的顺序
•当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet;
•如果值小于0或未指定时,则表示只有在第一次请求的容器才在该servlet调用初始化函数
•正值越小,servlet的优先级越高,应用启动时就越先加载。
•值相同时,容器就会自己选择顺序来加载。
配置的部分就是这样,然后我使用MyEclipse 9.1关联上Tomcat服务器。一切都是默认的设置,然后将本引用部署并启动Tomcat服务器。
这时候问题来了,我的任务类居然被创建了两次,下面是截取的部分日志数据:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
01.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
02.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
03.2011-11-01 19:09:03.878 计划任务被初始化了
04.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
05.2011-11-01 19:09:03,987 INFO [main] - org.quartz.core.QuartzScheduler.<init>(214) | Quartz Scheduler v.1.6.1-RC1 created.
06....
07.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.
08.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
09.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 plaincopy在CODE上查看代码片派生到我的代码片
01.<listener>
02. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
03.</listener>
04.
05.<context-param>
06. <param-name>contextConfigLocation</param-name>
07. <param-value>/WEB-INF/classes/applicationContext*.xml</param-value>
08.</context-param>
修改之后程序运行一切正常。个人推测,由于org.springframework.web.context.ContextLoaderListener和org.springframework.web.servlet.DispatcherServlet都能够加载applicationContext*.xml(“*”是通配符,表示所有以“applicationContext”开头的xml文件)。而两个类殊途同归,最终都将这些配置文件交给了Spring框架的Ioc容器进行实例化。因此每个类都会被实例化两次。
发现之前说的不完全正确,不应该删除web.xml中的如下节点
[html] view plaincopy在CODE上查看代码片派生到我的代码片
01.<listener>
02. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
03.</listener>
04.
05.<context-param>
06. <param-name>contextConfigLocation</param-name>
07. <param-value>/WEB-INF/classes/applicationContext*.xml</param-value>
08.</context-param>
因为该节点指派的applicationContext*.xml是用于实例化除servlet之外的所有对象的,可以说项目中绝大多数的service和dao层操作都由ContextLoaderListener传递给Spring来进行实例化。
在web应用中,web.xml还经常出现如下的配置:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
01.<!--全局Servlet调度配置 -->
02. <servlet>
03. <!--若设置 servlet-name为[name] -->
04. <!--则DispatcherServlet在实例化后会自动加载[name]-servlet.xml -->
05. <servlet-name>spring</servlet-name>
06. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
07. <init-param>
08. <param-name>contextConfigLocation</param-name>
09. <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 plaincopy在CODE上查看代码片派生到我的代码片
01.<Host name="localhost" appBase="" unpackWARs="true" autoDeploy="true"
02. xmlValidation="false" xmlNamespaceAware="false">
03.
04. <Context docBase="/usr/local/apache-tomcat-6.0.29/webapps/semwinner"
05. path="" reloadable="true"></Context>
06. <Context docBase="/usr/local/apache-tomcat-6.0.29/webapps/emarboxmanager"
07. path="/admin" reloadable="true"></Context>
08.</Host>
是Tomcat服务器的问题,修改conf目录下的server.xml。修改节点Host,将appBase属性由默认“webapps”设置为空("")即可,如下所示:
<Host name="localhost" appBase="" unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
<Context docBase="/usr/local/apache-tomcat-6.0.29/webapps/crm"
path="" reloadable="true"></Context>
<Context docBase="/usr/local/apache-tomcat-6.0.29/webapps/crm"
path="/admin" reloadable="true"></Context>
</Host>
把appBase设置为空即可!
去除了appBase="webapps"中的webapps变成了appBase="",因为web应用程序都是放在webapps这个目录下的,如果 不把“webapps“去掉,这里会调用一次quartz的任务调度,在接下来的“<Context path”中又会调用一次quartz的任务调度,所以就重复了2次
下面提供我的解决办法:
修改前的web.xml文件中的配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
上面的配置文件,让我的定时计划任务执行了2次,下面是修改后的web.xml中的配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
注意: 我只去掉了applicationContext后面的 * 号,明确指定了加载的配置文件。
下面给出一个例子:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
01.package net.csdn.blog.chaijunkukn;
02.
03.import java.text.SimpleDateFormat;
04.import java.util.Calendar;
05.import java.util.Locale;
06.
07.public class TimerTask {
08. public void printTimeStamp(){
09. 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,配置文件只是工程中的一部分):
[java] view plaincopy在CODE上查看代码片派生到我的代码片
01.<?xml version="1.0" encoding="utf-8"?>
02.<beans xmlns="http://www.springframework.org/schema/beans"
03. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04. xsi:schemaLocation="http://www.springframework.org/schema/beans
05. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
06. <!-- 注册定时器 -->
07. <bean id="timer"
08. class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
09. <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的配置:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
01.<?xml version="1.0" encoding="UTF-8"?>
02.<web-app id="WebApp_ID" version="2.4"
03. xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04. xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
05. <display-name>TaskTest</display-name>
06. <servlet>
07. <servlet-name>springapp</servlet-name>
08. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
09. <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>
•load-on-startup标记容器是否在启动的时候实例化并调用其init()方法的优先级。
•它的值表示servlet应该被载入的顺序
•当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet;
•如果值小于0或未指定时,则表示只有在第一次请求的容器才在该servlet调用初始化函数
•正值越小,servlet的优先级越高,应用启动时就越先加载。
•值相同时,容器就会自己选择顺序来加载。
配置的部分就是这样,然后我使用MyEclipse 9.1关联上Tomcat服务器。一切都是默认的设置,然后将本引用部署并启动Tomcat服务器。
这时候问题来了,我的任务类居然被创建了两次,下面是截取的部分日志数据:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
01.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
02.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
03.2011-11-01 19:09:03.878 计划任务被初始化了
04.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
05.2011-11-01 19:09:03,987 INFO [main] - org.quartz.core.QuartzScheduler.<init>(214) | Quartz Scheduler v.1.6.1-RC1 created.
06....
07.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.
08.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
09.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 plaincopy在CODE上查看代码片派生到我的代码片
01.<listener>
02. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
03.</listener>
04.
05.<context-param>
06. <param-name>contextConfigLocation</param-name>
07. <param-value>/WEB-INF/classes/applicationContext*.xml</param-value>
08.</context-param>
修改之后程序运行一切正常。个人推测,由于org.springframework.web.context.ContextLoaderListener和org.springframework.web.servlet.DispatcherServlet都能够加载applicationContext*.xml(“*”是通配符,表示所有以“applicationContext”开头的xml文件)。而两个类殊途同归,最终都将这些配置文件交给了Spring框架的Ioc容器进行实例化。因此每个类都会被实例化两次。
发现之前说的不完全正确,不应该删除web.xml中的如下节点
[html] view plaincopy在CODE上查看代码片派生到我的代码片
01.<listener>
02. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
03.</listener>
04.
05.<context-param>
06. <param-name>contextConfigLocation</param-name>
07. <param-value>/WEB-INF/classes/applicationContext*.xml</param-value>
08.</context-param>
因为该节点指派的applicationContext*.xml是用于实例化除servlet之外的所有对象的,可以说项目中绝大多数的service和dao层操作都由ContextLoaderListener传递给Spring来进行实例化。
在web应用中,web.xml还经常出现如下的配置:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
01.<!--全局Servlet调度配置 -->
02. <servlet>
03. <!--若设置 servlet-name为[name] -->
04. <!--则DispatcherServlet在实例化后会自动加载[name]-servlet.xml -->
05. <servlet-name>spring</servlet-name>
06. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
07. <init-param>
08. <param-name>contextConfigLocation</param-name>
09. <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 plaincopy在CODE上查看代码片派生到我的代码片
01.<Host name="localhost" appBase="" unpackWARs="true" autoDeploy="true"
02. xmlValidation="false" xmlNamespaceAware="false">
03.
04. <Context docBase="/usr/local/apache-tomcat-6.0.29/webapps/semwinner"
05. path="" reloadable="true"></Context>
06. <Context docBase="/usr/local/apache-tomcat-6.0.29/webapps/emarboxmanager"
07. path="/admin" reloadable="true"></Context>
08.</Host>
是Tomcat服务器的问题,修改conf目录下的server.xml。修改节点Host,将appBase属性由默认“webapps”设置为空("")即可,如下所示:
<Host name="localhost" appBase="" unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
<Context docBase="/usr/local/apache-tomcat-6.0.29/webapps/crm"
path="" reloadable="true"></Context>
<Context docBase="/usr/local/apache-tomcat-6.0.29/webapps/crm"
path="/admin" reloadable="true"></Context>
</Host>
把appBase设置为空即可!
去除了appBase="webapps"中的webapps变成了appBase="",因为web应用程序都是放在webapps这个目录下的,如果 不把“webapps“去掉,这里会调用一次quartz的任务调度,在接下来的“<Context path”中又会调用一次quartz的任务调度,所以就重复了2次
下面提供我的解决办法:
修改前的web.xml文件中的配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
上面的配置文件,让我的定时计划任务执行了2次,下面是修改后的web.xml中的配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
注意: 我只去掉了applicationContext后面的 * 号,明确指定了加载的配置文件。
发表评论
-
Spring Boot
2017-09-26 09:51 290Spring Boot是由Pivotal团 ... -
spring AOP中切点
2017-08-25 09:59 905在spring AOP中,需要使用AspectJ的切点表达式 ... -
Spring JdbcTemplate详解
2017-07-19 16:12 593JdbcTemplate简介 Spring对数据库的操 ... -
Spring相关
2017-04-20 16:10 458我是一个Java开发者,之前知道Spring属于这个公司,就 ... -
spring.schemas、spring.handlers的使用
2017-02-28 13:55 1723报错信息:Configuration problem: Un ... -
Spring的一个命名空间的名称空间处理程序没有找到
2017-02-25 15:20 9461. 问题 本文将讨论Spring中最常见的配置问题 —— ... -
到底EJB是什么
2016-12-06 10:05 452到底EJB是什么?被口口相传的神神秘秘的,百度一番,总觉得 ... -
Spring MVC 和 Servlet 一样,都不是线程安全的
2016-04-28 01:06 680你的理解是对的,Spring MVC 和 Servlet 一 ... -
springmvc的control 的线程是否安全的问题
2016-05-31 10:09 363关于java Servlet,Struts,springM ... -
框架的一些学习
2016-02-03 14:53 264java aopalliance-1.0.jar这个包是AOP ... -
Metrics介绍和Spring的集成
2016-02-02 16:56 975Metrics可以为你的代码的运行提供无与伦 ... -
spring mvc常用的注解
2016-01-22 14:28 706spring mvc常用的注解: ... -
Spring的常用注解
2016-01-20 16:07 658Spring2.5引入注解式处理器 @Controlle ... -
通过Spring的配置,添加多个数据源,制作多个qlMapClient,iBatis或Hibernate的各个DAO
2016-12-27 10:25 519通过Spring的配置,添加多个数据源,制作多个qlMapCl ... -
springmvc避免IE执行AJAX时,返回JSON出现下载文件
2017-01-01 23:35 865<!-- 避免IE执行AJAX时,返回JSON出现下载文 ... -
springMVC的@ResponseBody出现乱码解决方法
2017-01-02 00:23 381使用@ResponseBody出现乱码解决方法 1、 Re ... -
Spring中的Bean的注入方式
2017-01-02 00:27 540一 setter方法注入 配置文件如下: <bean ... -
spring发送邮件配置文件
2017-01-02 00:27 12761、发送邮件配置文件springmail_config ... -
@Resource和@Autowire的区别
2017-01-02 00:27 701@Resource和@Autowire的区别 在java代码中 ... -
Spring中继承并简化了Quartz
2017-01-02 00:27 673Quartz是一个强大的企业级任务调度框架,Spring中继承 ...
相关推荐
一个tomcat下部署了两个应用,一个是普通web应用syncc,另一个应用syncc_wx属于微信公众号后台程序涉及消息定时推送,tomcat未分离...”spring定时任务执行两次的异常排查处理.docx"针对上述描述问题进行分析和解决。
当我们遇到Spring定时器执行两次或者更多次的问题时,这通常是由于配置不当或者多线程并发导致的。下面将详细介绍如何使用Spring集成Quartz,以及解决定时任务重复执行的问题。 首先,让我们了解Spring如何配置...
Spring 定时任务执行两次及 Tomcat 部署缓慢问题的解决方法 Spring 定时器执行两次问题重现和解析 在使用 Quartz 定时任务框架时,可能会出现定时任务执行两次的问题。这个问题可能会在开发环境中没有出现,但是...
标题中的“spring定时器启动两次原因及解决”指...总之,解决Spring定时任务启动两次的问题需要从配置、代码逻辑和环境设置等多个角度进行排查,结合源码理解和日志分析,才能准确找到问题的根源并提出有效的解决方案。
在多应用服务器负载均衡环境下,Spring Quartz定时任务的重复执行问题是一个常见的挑战。Spring Quartz是一个强大的、开源的作业调度框架,允许开发者定义和执行复杂的定时任务。然而,当多个服务器实例并行运行时,...
一、Spring定时任务简介 Spring框架的定时任务功能主要依赖于`Spring Task`模块,也称为Spring的后台任务处理。它提供了基于`@Scheduled`注解和`TaskScheduler`接口的两种定时任务实现方式。`@Scheduled`适用于简单...
给定的压缩包可能包含了一个关于如何配置、使用和测试Spring定时任务的文档。这个文档应该详细介绍了每个步骤,包括如何在Spring环境中注册和启动定时任务,如何编写带有`@Scheduled`注解的方法,以及如何编写测试...
`fixedRate`参数定义了两次执行之间的间隔时间。 如果需要更复杂的调度规则,如cron表达式,可以使用`cron`属性: ```java @Scheduled(cron = "0 0/5 * * * ?") public void executeTask() { // 执行任务代码 } `...
Spring定时任务是Spring框架中的一个强大特性,它允许开发者在应用程序中设置定时任务,以便在特定的时间点或按照预设的周期执行特定的业务逻辑。这个"spring定时任务demo包含jar包"提供了一个完整的示例,帮助我们...
Spring定时任务基础 Spring的定时任务功能是通过`org.springframework.scheduling`包中的类来实现的,主要涉及`TaskScheduler`和`TaskExecutor`接口。`TaskScheduler`用于定时任务的调度,而`TaskExecutor`则处理...
在Spring框架中,定时任务是通过Spring的Task模块来实现的,这允许我们在应用程序中创建和管理定时任务,而无需依赖外部的调度器如Quartz或Cron。本例主要探讨如何在Spring中配置和执行定时任务。 首先,我们要引入...
在Spring框架中,定时任务是实现周期性任务执行的关键特性,它允许开发者在特定时间间隔内执行特定的代码逻辑,而无需手动干预。本示例将深入探讨如何使用Spring的TaskScheduler或者Quartz Scheduler来创建和管理...
Spring通过`@Scheduled`注解提供了对定时任务的支持,该注解可以轻松地应用于任何Java方法上,使得开发者能够以声明式的方式来配置和执行定时任务。 ### @Scheduled 注解详解 `@Scheduled`注解主要用于方法级别,...
本资源"Spring整合Quartz后的简单定时任务示例"提供了如何将这两者结合使用的实例,旨在帮助开发者实现基于Spring的定时任务功能。 首先,我们要理解Spring对定时任务的支持。Spring框架通过`@Scheduled`注解提供了...
### Spring3.2.6定时任务与线程池配置详解 #### 一、背景介绍 在现代软件开发中,为了提高系统的并发处理能力和资源利用率,往往需要利用到多线程技术来实现定时任务的处理。Spring框架作为Java企业级应用开发中的...
本文将详细讲解两种通过Spring实现定时任务的方法:Spring的`TimerTask`和`Spring Batch`的`Tasklet`。我们将涵盖这两种方法的基本原理、配置以及使用源码,确保你能全面理解如何在实际项目中应用。 ### 一、Spring...
首先,我们需要引入Spring Boot的`spring-boot-starter-quartz`或者`spring-boot-starter-task`依赖,这两个都是Spring框架提供的定时任务支持。`spring-boot-starter-quartz`基于Quartz库,而`spring-boot-starter-...
### Spring定时任务的几种实现 #### 一、定时任务实现技术分类 在Spring框架中,实现定时任务的主要技术方案有三种: 1. **Java自带的`java.util.Timer`类**:这种实现方式允许用户调度一个`java.util.TimerTask`...
在SpringBoot中创建定时任务,主要有两种方式:一种是通过注解(@Scheduled)创建静态定时任务,另一种是通过实现接口(SchedulingConfigurer)创建动态定时任务。 静态定时任务的创建非常简单,只需几行代码便可以完成...
这里的`executeTask`方法会被Spring定时任务框架自动调用,每60秒执行一次。 3. **集成iBatis** iBatis是一个轻量级的持久层框架,它允许开发者将SQL语句写在XML配置文件中,与Java代码分离,提高可维护性。要在...