1. 程式人生 > >分析解決 spring quartz 中出現的執行兩次問題

分析解決 spring quartz 中出現的執行兩次問題

color src bat class 故事 重復 功能 fig 再次

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>

再次啟動工程,問題解決。

分析解決 spring quartz 中出現的執行兩次問題