分析解決 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>

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM