使用spring的定时任务时遇到重复执行

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用spring的定时任务时遇到重复执行相关的知识,希望对你有一定的参考价值。

参考技术A spring自带的定时任务,能解决很多问题。在当前公司的项目模块中,我使用了这一功能。然而因为服务器配置不当,引发了任务重复执行。困扰我多日。

公司当前业务中涉及到统计模块。该模式我使用了spring的定时任务。其中一个任务每日的凌晨4点执行一次。但是结果发现执行了2次,产生2条记录。

寻找原因的时候,基本都是 通过搜索引擎,很幸运,不是我一个人遇到,大家都遇到类似的问题。

阅读几篇文章分析之后,得出的结论如下:

具体什么样子的配置会导致项目加载2次呢。

主要是tomcat的server.xml中 host和context参数。

出现问题时的配置如下:

tomcat 会自动加载webapps下文件夹作为项目。访问路径为 localhost:8080/项目文件夹名

如果配置了context,则tomcat 会加载一次context的文件夹作为默认项目。

最终导致 D:\Program Files\apache-tomcat-8.5.23\webapps\lightai-api 被2次加载,问题出现。

而当初原本配置context是为了实现访问 localhost:8080 这样访问项目,由于不熟悉这一加载机

制,引发了这个故障。

如果需要在美化项目的访问路径,可以通过nginx来实现。

当前我使用的第一种方案。

Spring 定时任务重复执行的问题分析

Spring 定时任务重复执行的问题分析


背景:使用quartz时客户现场不知道为什么跑着跑着就停了,后来决定换成spring定时任务。


当使用spring定时任务时莫名奇妙的就是同一时间重复执行多次任务(通常情况下执行两次,有时候会达到3次)。下面记录过程并逐一分析说明,供以后参考;


1、分析原因后发现是由ClassPathXmlApplicationContext导致

通过n多次试验发现:

    当任务方法中不含任何业务逻辑时(如:只打印一些标志性的信息),任务能够正常执行,没有重复执行的现象;

    当任务方法中包含业务逻辑,或应用程序执行别的请求任务时,均可能导致重复执行;

最终定位到了,只要执行ServletUtil.getBean("xxxxxxxx");程序获取对象,就会导致重复执行。


1.1 在执行任务的程序中,使用到的对象加载方式如下:

ColumnService columnService = (ColumnService) ServletUtil.getBean("columnServiceImpl");


1.2 ServletUtil 的getBean 方法如下:

public static Object getBean(String beanId)

{

if(factory == null)

factory = new ClassPathXmlApplicationContext("applicationContext.xml");

Object  o = null ;

try{

o = factory.getBean(beanId);

}catch(Exception e){

System.out.println("获取bean失败");

}

return o;

}


分析发现,在Tomcat容器启动时会扫描bean初始化加载spring上下文环境;然而当显式的这样调用的时候,会再次加载bean,初始化spring上下文环境。相当于容器里除了刚启动时的一套之外又产生了一条spring上下文,当然定时任务也有了两套。 

这里还说明另一个问题,单实例的bean并不是“单例模式”,只是保证一套spring上下文里只有一个bean实例。


2、应对策略


总算是找到原因了,于是考虑换一个对象获取方式,在伟大的网络中找到了答案,使用 ApplicationContextAware 接口可有效避免此问题。


2.1 重写bean获取工具类:


public class SpringContextUtil implements ApplicationContextAware {  

  

    // Spring应用上下文环境  

    private static ApplicationContext applicationContext;  

  

    /** 

     * 实现ApplicationContextAware接口的回调方法,设置上下文环境 

     *  

     * @param applicationContext 

     */  

    public void setApplicationContext(ApplicationContext applicationContext) {  

        SpringContextUtil.applicationContext = applicationContext;  

    }  

  

    /** 

     * @return ApplicationContext 

     */  

    public static ApplicationContext getApplicationContext() {  

        return applicationContext;  

    }  

  

    /** 

     * 获取对象 

     * 这里重写了bean方法,起主要作用 

     * @param name 

     * @return Object 一个以所给名字注册的bean的实例 

     * @throws BeansException 

     */  

    public static Object getBean(String name) throws BeansException {  

        return applicationContext.getBean(name);  

    }  


分析:加载Spring配置文件时,如果Spring配置文件中所定义的Bean类实现了ApplicationContextAware 接口,那么在加载Spring配置文件时,会自动调用ApplicationContextAware 接口中的

public void setApplicationContext(ApplicationContext context) throws BeansException 方法,获得ApplicationContext对象。 前提必须在Spring配置文件中指定该类


2.2 配置spring 文件 applicationContext.xml,如下


    <bean id="SpringContextUtil" class="com.carnation.utils.SpringContextUtil" lazy-init="false"></bean>


    如上配置一定要注意当spring配置default-lazy-init="true" 时,此类的配置一定要指定 lazy-init="false",否则无法通过此类获取到bean(会报null异常)


2.3 改变bean的获取方式


    将原始使用 ServletUtil.getBean("xxxxxxxx"); 获取bean的全部修改为 SpringContextUtil.getBean("xxxxxxxx"); 如下:

    

    UserService userService= (UserService)SpringContextUtil.getBean("userServiceImpl");

    DepartmentService departmentService = (DepartmentService)SpringContextUtil.getBean("departmentServiceImpl");

    UserRoleService userRoleService = (UserRoleService)SpringContextUtil.getBean("userRoleServiceImpl");

    SyncRoService syncRoService = (SyncRoService) SpringContextUtil.getBean("syncRoServiceImpl");


    到此,定时任务重复执行的问题得到解决(这里只分析了我在实际的场景下遇到的问题,但并不一定适合所有)


其它参考网址 http://zoroeye.iteye.com/blog/2186822




本文出自 “xxxxxxxxxxx” 博客,请务必保留此出处http://huxy534.blog.51cto.com/9338042/1924684

以上是关于使用spring的定时任务时遇到重复执行的主要内容,如果未能解决你的问题,请参考以下文章

spring中定时器每周执行两次

Spring 定时执行任务重复执行多次

使用spring@Scheduled进行任务定时

Spring 定时任务 @Scheduled cron表达式

Spring 定时任务实现 以及无法正常执行分析

多节点服务器定时任务重复处理的问题