spring定时器,定时器一次执行两次的问题

本人遇见问题不是web.xml中加载两次applicationContext导致的各bean加载两次,而是在tomcat中server.xml中Host的appBase为webapps,在context中又加载了。把appBase设为“”好使;另外,从网上看到把Host的节点的autoDeploy unpackWARs还有reloadable都致为false也可行,还有一种不加context也是可行的。

另外就是判断是否重复执行定时任务:https://blog.csdn.net/caomiao2006/article/details/51338254;这个没有试过,待尝试。

分别如下:

一:这种方法不会在webapps下解压出对应文件,在work/Catalina/localhost/-下,有对应项目执行class等

            unpackWARs="true" autoDeploy="true">
                        prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />
        
      

二:去掉Context标签,显示完整,会解压war包,但是不能定义访问路径和指定多项目。

            unpackWARs="true" autoDeploy="true">
                        prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />
       
      

 

转自:https://blog.csdn.net/bbj12345678/article/details/78530428

今天在做一个项目的时候用到了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,配置文件只是工程中的一部分): 

 

[java] view plain copy

  1.   
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  4.        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  
  5.       
  6.     
  7.         class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
  8.           
  9.               
  10.                   
  11.               
  12.           
  13.       
  14.       
  15.       
  16.           
  17.               
  18.           
  19.           
  20.               
  21.             0/3 * * * * ?  
  22.           
  23.       
  24.       
  25.     
  26.         class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
  27.           
  28.               
  29.           
  30.           
  31.             doTask  
  32.           
  33.           
  34.       
  35.       
  36.       
  37.   


web.xml的配置: 

 

 

 

[java] view plain copy

  1.   
  2.     xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
  4.     TaskTest  
  5.       
  6.         springapp  
  7.         org.springframework.web.servlet.DispatcherServlet  
  8.           
  9.             contextConfigLocation  
  10.             /WEB-INF/classes/applicationContext*.xml  
  11.           
  12.         1  
  13.       
  14.   
  15.       
  16.         springapp  
  17.         *.htm  
  18.       
  19.   
  20.       
  21.         EncodingFilter  
  22.         com.ku6.tech.wap.filter.EncodingFilter  
  23.           
  24.             encoding  
  25.             utf-8  
  26.           
  27.           
  28.             forceEncoding  
  29.             true  
  30.           
  31.       
  32.       
  33.       
  34.         EncodingFilter  
  35.         *.htm  
  36.       
  37.   
  38.       
  39.         404  
  40.         /error.jsp  
  41.       
  42.   
  43.       
  44.         index.jsp  
  45.       
  46.   
  47.       
  48.         org.springframework.web.context.ContextLoaderListener  
  49.       
  50.   
  51.       
  52.         contextConfigLocation  
  53.         /WEB-INF/classes/applicationContext*.xml  
  54.       
  55.   

 

 

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

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

 

 

[java] 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.(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.(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.(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.(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.   
  2.     org.springframework.web.context.ContextLoaderListener  
  3.   
  4.   
  5.   
  6.     contextConfigLocation  
  7.     /WEB-INF/classes/applicationContext*.xml  
  8.   


修改之后程序运行一切正常。个人推测,由于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.   
  2.     org.springframework.web.context.ContextLoaderListener  
  3.   
  4.   
  5.   
  6.     contextConfigLocation  
  7.     /WEB-INF/classes/applicationContext*.xml  
  8.   


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

 

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

 

[html] view plain copy

  1.   
  2.       
  3.           
  4.           
  5.         spring  
  6.         org.springframework.web.servlet.DispatcherServlet  
  7.           
  8.             contextConfigLocation  
  9.             classpath:servletContext.xml  
  10.           
  11.           
  12.         1  
  13.       
  14.       
  15.         spring  
  16.         *.do  
  17.       


这个是用来处理所有servlet的,没有它就无法通过请求地址来调用相应的Controller。
这里我明确地指示了要加载类路径下的servletContext.xml,如果不指定,则会按照注释中所描述地那样自动加载spring-servlet.xml
无论是servletContext.xml还是applicationContext*.xml都可以按照......这样的形式来配置。
问题来了,有时候不注重对象初始化的分类,尤其是使用这样的包扫描形式统一初始化,
很容易造成满足条件的对象被初始化两次,那么在计划任务的时候被执行两次也就不奇怪了。其实说来说去,还是要提醒大家,不同的配置文件其作用是不一样的,
不要将所有的初始化操作都放到一个配置文件中,更不要重复配置。不仅浪费资源,还很容易导致莫名其妙的故障。

 

 

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

 

 

[html] view plain copy

  1.     xmlValidation="false" xmlNamespaceAware="false">  
  2.   
  3.     
  4.         path="" reloadable="true">  
  5.     
  6.         path="/admin" reloadable="true">  
  7.     

 

 

但是本人尝试之后并没有起作用。可能不适用于我遇到的这个问题。写出上面解决方法的作者认为web应用程序默认都是放在webapps这个目录下的,如果不把“webapps“去掉,这里会调用一次quartz的任务调度,在接下来的“

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

 

[html] view plain copy

  1.   
  2. org.springframework.web.context.ContextLoaderListener  
  3.   
  4.   
  5. contextConfigLocation  
  6. classpath:applicationContext*.xml  
  7.   
  8.   
  9. spring  
  10. org.springframework.web.servlet.DispatcherServlet  
  11.   
  12. contextConfigLocation  
  13. classpath:spring-servlet.xml  
  14.   
  15. 1  
  16.   


listener--context-param这段配置是负责依赖注入的,配置文件名称支持正则匹配。这里是关键,你要看看所有匹配规则的配置文件中是否存在重复注入bean的现象;
servlet这段是负责请求URL请求处理转发到哪个Bean上的。
希望对你有帮助。

 

 

关键:spring-servlet.xml 文件负责的是url 的转发,而 applicationContext.xml 负责的是bean 的注入,两者负责的工作不一样,所以在 web.xml 文件中配置的时候,就需要注意,DispatcherServlet 的初始化参数是spring-servlet.xml,而ContextLoaderListener的初始化参数才是applicationContext.xml 文件呢。

 

 

经过本人测试发现第二种:修改 server.xml 文件的方式是可以的,反而第一种方式不起作用。

你可能感兴趣的:(java,定时任务,加载2次)