[關鍵字:重復執行、重復調用、每次執行兩次、執行2次]
前言:
先說一下,項目背景。由於組內某成員在用Maven搭建項目時不規范,導致項目的名稱與實際訪問項目名稱不一致。
在部署項目時,必需要配一下虛擬路徑,映射到那個項目所在目錄下去,才能正常訪問。
舉個例子:項目名稱叫student-web,部署到Tomcat-webapps下,本地環境正常情況下的訪問url應該是:
127.0.0.1:8080/student-web
而實際訪問的url需要這樣:
127.0.0.1:8080/student
0x001: 初探
那首先想到問題的解決方案就是在Tomcat的server.xml內配置虛擬路徑,來映射到實際項目。比如這樣:
1 <Host .......> 2 <Context path="/student" docBase="D:\apache-tomcat\webapps\student-web" reloadable="true"/> 3 </Host>
吶,一開始以為這樣問題就解決了。后來發現,實則不是。這樣做的后果是項目會被容器實例化兩次。
0x002: why?
首先需要了解<Host>標簽中的appBase屬性和<Context>標簽中的docBase屬性的作用和區別是什么?
appBase屬性:這個目錄下面的子目錄將自動被部署為web應用,且war文件將被自動解壓縮並部署為web應用(默認為Tomcat下webapps目錄)注意這句話所說的每件(個)事(點)都可以被重新配置或取消。
docBase屬性: docBase屬性位於<Context>標簽中,而<Context>標簽的作用是用於指向不在webapps下的應用的所在目錄,在tomcat啟動時docBase屬性指向的目錄下的應用也被作為web項目同時啟動。
在有了以上了解后,那Quartz每次調度時被執行兩次方法的問題原因就找到了。
0x003: 解決方案
1.將<Host>標簽內的<Context>標簽去除,讓Tomcat自動去掃描webapps下的應用並部署。
2.若 ‘必需使用<Context>標簽’ 且 ‘必需配置虛擬路徑映射’ (注意這句話,后邊解釋),則必需將項目移出webapps目錄至某個新目錄,同時將<Context>標簽中的docBase屬性指向該新移至的目錄,如下圖
解釋一下第2條的前半句,經過測試發現,將student-web項目放到webapps目錄,且同時配置<Context>標簽的path屬性為“/項目名稱”,啟動Tomcat,此時項目並不會跑兩遍,還是一遍,因為path屬性指定的值還是項目名稱,等於沒配置。如下:
1 <Host .......> 2 <Context path="/student-web" docBase="D:\apache-tomcat\webapps\student-web" reloadable="true"/> 3 </Host>
若是配置<Context>標簽的path屬性值為 “/非項目名稱” 且 docBase屬性指向webapps目錄,那項目肯定會被容器實例化兩遍!如下:
1 <Host .......> 2 <Context path="/student" docBase="D:\apache-tomcat\webapps\student-web" reloadable="true"/> 3 </Host>
至於選擇哪種解決方案,根據實際情況定,那我這里只能選擇第2種。
0x004: 聲明
導致Quartz調度任務被執行兩次的原因有很多,以上列舉的2種解決方案 可能 並 不適合你。亦可從其他方向查找原因。
比如,檢查Quartz的xml配置文件被加載了2次等等。
0x005: 完結
分享是技術進步的源泉,作者能力有限,如有錯誤,歡迎指出,不吝賜教。