分析解决 spring quartz 中出现的执行两次问题

1. 问题描述

在开发询盘功能时,遇到一个需求,就是后台定时任务执行用电施工业务的工单下发。

使用的技术是 spring quartz,因为其他应用有先例,配置quartz 完成后,先写了一个 helloworld 测试下。

然而却发现,每次到定时时间后,程序都会执行两次。

2. 分析过程

先使用 bing 搜索了下看别人是否也遇到过类似问题,果然有。

http://blog.csdn.net/jiang117/article/details/43077275

上面文档的作者,查找的原因是 ContextLoaderListener 和 DispatcherServlet 对应用上下文重复加载,导致问题出现。

给出的解决方法如下:

带着这个疑惑,我检查一下自己项目的 web.xml 文件,发现果然有问题。

下面是 ContextLoaderListener 中加载的上下文。

  <!-- 加载Spring和Mybatis的配置信息 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/spring/spring-all.xml</param-value>
    </context-param>
    <!-- Spring监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

这是 DispatcherServlet 加载的上下文

        <!-- Spring MVC servlet -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/classes/spring/spring-all.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

经过对比发现,两个上下文都会加载 /WEB-INF/classes/spring/spring-all.xml, spring-all.xml 文件则包含了所有的 spring 配置文件,也就是所有的上下文配置。

这样就会产生一个问题,就是  spring-all .xml 上下文中所有的配置都会被实例化两次,因此也就会导致该问题出现。

3. 解决过程

找到了问题原因,下一步就要修改 web.xml 中的配置,解决 spring-all xml 上下文被实例化两次的问题。

解决问题之前,先要弄清楚 DispatcherServlet 和 ContextLoaderListener 这两个应用上下文之间的关系。

下面的内容选自 《spring 实战 第4版》 p139

两个应用上下文之间的故事

当 DispatcherServlet 启动的时候,它会创建 Spring 上下文,并加载配置文件或者配置类中所声明的 bean。

同时在 Spring Web 应用中,通常还有一个另外的应用上下文,它由 ContextLoaderListener 创建。

两者的分工有所不同, DispatcherServlet 中加载 Web 组件的 bean,如 Controller,viewResolver 以及处理器映射。而ContextLoaderListener 要加载应用中其他的 bean,这些 bean 通常是驱动应用后端的中间层和数据层组件。

同时在如下博客链接 http://www.cnblogs.com/weknow619/p/6341395.html 得到说明:

因此决定使用 ContextLoaderListener 加载所有配置,而将 DispatchServlet 上下文去除。

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/spring/spring-all.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
        <!-- Spring MVC servlet -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

再次启动工程,问题解决。

时间: 2024-10-06 07:43:00

分析解决 spring quartz 中出现的执行两次问题的相关文章

解决Spring+Quartz无法自动注入bean问题

问题 我们有时需要执行一些定时任务(如数据批处理),比较常用的技术框架有Spring + Quartz中.无奈此方式有个问题:Spring Bean无法自动注入. 环境:Spring3.2.2 + Quartz1.6.1 Quartz配置: <bean id="traderRiskReportJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"

Spring Quartz定时任务不准时执行

1. 前言 也是前段时间工作上遇到过这样的问题:quartz定时任务没有在预期的时间执行.后来研究了下quartz的机制,查明了原因,这里做个记录和分享. 2. 原因解释 先看一下spring quartz的大致机制或者说原理.quartz任务由一个主线程和线程池中的多个具体的工作线程构成. 主线程是QuartzSchedulerThread, 主要负责获取具体的定时任务和该任务执行的时间(比如可以通过cron expression 得到时间),并分发任务给线程池. 具体的任务由线程池中的工作线

解决spring配置中的bean类型的问题:BeanNotOfRequiredTypeException

解决spring配置中的bean类型的问题:BeanNotOfRequiredTypeException这个问题出现的原因:一般在使用annotation的方式注入spring的bean 出现的,具体是由于spring采用代理的机制导致的,看使用的代码: Java代码 1. 使用类注入: @Resource(name = "aisleService") private AisleService aisleService; 2. 使用接口注入: @Resource(name = &quo

用 OpenSessionInViewInterceptor 的思路解决 Spring框架中的Hib

众所周知, 为了解决 Hibernate Lazy 问题, Spring 中引入了 OpenSessionInViewInterceptor, 这样虽然解决了页面上的 Lazy Load 问题,却增加了各层之间的偶合性, 如果一个 Lazy 的 Collection 在页面上可以被正确的 load, 但是如果请求不是来自于 HttpServletRequest (比如在 TestCase 或 Service 中希望获取 lazy 的属性), 一般会导致两种错误: 代码 [java] view p

解决Spring+Quartz不能注入Bean的问题

Spring application-quartz的配置<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http:

解决Spring Cloud中Feign/Ribbon第一次请求失败的方法

前言 在Spring Cloud中,Feign和Ribbon在整合了Hystrix后,可能会出现首次调用失败的问题,要如何解决该问题呢? 造成该问题的原因 Hystrix默认的超时时间是1秒,如果超过这个时间尚未响应,将会进入fallback代码.而首次请求往往会比较慢(因为Spring的懒加载机制,要实例化一些类),这个响应时间可能就大于1秒了.知道原因后,我们来总结一下解决放你. 解决方案有三种,以feign为例. 方法一 ? 1 hystrix.command.default.execut

解决Spring Cloud中Feign第一次请求失败的问题

在Spring Cloud中,Feign和Ribbon在整合了Hystrix后,可能会出现首次调用失败的问题 com.netflix.hystrix.exception.HystrixTimeoutException: null at com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$1.run(AbstractCommand.java:1142) ~[hystrix-core-1.5.18.jar:1.5.

Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题

Spring AOP底层的动态代理实现有两种方式:一种是JDK动态代理,另一种是CGLib动态代理. JDK动态代理 JDK 1.3版本以后提供了动态代理,允许开发者在运行期创建接口的代理实例,而且只能为接口创建代理实例. 如果被代理目标没有接口那么Spring也无能为力,Spring通过Java的反射机制生成被代理接口的新的匿名实现类. JDK动态代理具体实现原理: 通过实现InvocationHandlet接口创建自己的调用处理器: 通过为Proxy类指定ClassLoader对象和一组in

Spring Boot 中实现定时任务的两种方式

在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Quartz ,Spring Boot 源自 Spring+SpringMVC ,因此天然具备这两个 Spring 中的定时任务实现策略,当然也支持 Quartz,本文我们就来看下 Spring Boot 中两种定时任务的实现方式. @Scheduled 使用 @Scheduled 非常容易,直接创建一个