Tomcat7 使用 Scheduler

Java EE Server 上寫一個排程工作,只要加一個 @Schedule 就可以了,Tomcat 除了用 Java SE 的 TimerTask 來排程外的另一個選擇就是 quartz,看了一下有支援 Thread Pool,設定檔不用寫在程式碼上,之後要寫 ant 來置換比較方便,就決定用 quartz。

使用版本

Tomcat7 + quartz 2.1.7

步驟

http://www.quartz-scheduler.org/documentation/quartz-2.1.x/quick-start 是一個官網的簡單使用說明,下面是我自己使用的筆記。

1) 安裝

官網下載,解壓縮後 lib 下的 jar 檔都加入專案的 build path。

2) 啟用 quartz

web.xml 加入 QuartzInitializerListener,QuartzInitializerListener 實作了 javax.servlet.ServletContextListener,QuartzInitializerListener 在 Web App 啟動後就會初始化 quartz 相關的設定。

WebContent/WEB-INF/web.xml
<servlet>
<servlet-name>QuartzInitializer</servlet-name>
<servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class>
<init-param>
<param-name>shutdown-on-unload</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>wait-on-shutdown</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>start-scheduler-on-load</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>


3) 設定 quartz

WebContent/WEB-INF/classes/quartz.properties
org.quartz.threadPool.threadCount=2 # 用2個 Thread
org.quartz.plugin.jobInitializer.class=org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin # 用 XML(quartz_data.xml) 設定排程工作

4) 設定排程工作

quartz_data.xml 內,
  • 建立一個 Job,取名並指定實作類別。
  • 建立一個 Trigger,取名,指定 Job 和執行時間。
關於 Trigger 的執行時間設定可參考:http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger

WebContent/WEB-INF/classes/quartz_data.xml
<?xml version="1.0" encoding="UTF-8"?>
<job-scheduling-data
xmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd"
version="1.8">
<schedule>
<job>
<name>FooJob</name>
<job-class>com.tangblack.quartz.example.FooJob</job-class>
</job>
<!-- cron-expression: Seconds Minutes Hours DayOfMonth Month DayOfWeek Year -->
<trigger>
<cron>
<name>FileJobTrigger</name>
<job-name>FooJob</job-name>
<cron-expression>0 0/1 * * * ? *</cron-expression>
</cron>
</trigger>
</schedule>
</job-scheduling-data>

5) 實作排程工作

FooJob.java
public class FooJob implements Job
{
  @Override
  public void execute(final JobExecutionContext ctx) throws JobExecutionException 
  {
    // To something here!
    }
}

問題

1) 執行時發生 java.lang.NoClassDefFoundError: javax/transaction/UserTransaction

嚴重: Exception sending context initialized event to listener instance of class org.quartz.ee.servlet.QuartzInitializerListener

java.lang.NoClassDefFoundError: javax/transaction/UserTransaction

下載 jta-1.1.jar 後,加入專案的 build path。


2) Tomcat7 關閉 Web App 出現 memory leak 警告。

[DefaultQuartzScheduler_Worker-5] but has failed to stop it. This is very likely to create a memory leak

這是因為 Tomcat7 關閉 Web App 時,沒有正確關閉 quartz 的關係,在QuartzInitializerListener 加入下列初始參數。

WebContent/WEB-INF/web.xml
<servlet>
<servlet-name>QuartzInitializer</servlet-name>
<servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class>
<init-param>
<param-name>shutdown-on-unload</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>wait-on-shutdown</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>start-scheduler-on-load</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

參考

0 則回應: