2013年11月12日 星期二
Quartz - 出現org.quartz.SchedulerException: Problem instantiating class...
問題:出現org.quartz.SchedulerException: Problem instantiating class 導致JOB無法順利被初始化執行
請檢查Job Class是否有實做default construction
2013年5月19日 星期日
Quartz初體驗 - 如何關閉煩人的console output 改用 file方式記錄?
(以quartz 2.1.6為例)
- 所需lib:quartz-all-2.1.6.jar、slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.1.jar、log4j-1.2.16.jar、c3p0-0.9.1.1.jar (直接至quartz官方網站就可下載)
- 創建檔案 log4j.properties,內容如下:
# Root logger option log4j.rootLogger=INFO, file # Direct log messages to a log file log4j.appender.file=org.apache.log4j.RollingFileAppender log4j.appender.file.File=C:\\loging.log log4j.appender.file.MaxFileSize=1MB log4j.appender.file.MaxBackupIndex=1 log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n org.quartz.logger.schedLogger.class = org.quartz.impl.Log4jLogger org.quartz.logger.schedLogger.categoryName = scheduler
log4j.appender.file.File=C:\\loging.log 可自行更改為所需的file outputf路徑
log4j.rootLogger=INFO, file 自行更改所需的LOG LEVEL,共有:
TRACE > DEBUG > INFO > WARN > ERROR > FATAL - 創建檔案 quartz.properties,內容如下:
org.quartz.scheduler.instanceName = MyScheduler org.quartz.threadPool.threadCount = 3 org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore org.quartz.logger.schedLogger.class = org.quartz.impl.Log4jLogger
- 完成,再下來就是寫CODE囉
2013年4月6日 星期六
Quartz初體驗 - Jobs and Triggers介紹
- Schedule:用來掌管所有需要執行的Job,包含呼叫Job execute(...)
- Job :所需要執行的內容Class都需implements 此 interface
- JobDetail :用來定義Job instances
- JobBuilder :用來建立JobDetail
- Trigger :設定實際運作Job的執行細節,例如:執行時間狀態
- TriggerBuilder :用來建立Trigger
常用Trigger:
- SimpleTrigger
使用狀況:一次性執行、指定時間執行(可重複N次)、間隔延遲指定時間執行... - CronTrigger
使用狀況:指定日期執行,例如:每個星期五早上十點執行、每個月的10號下午兩點執行...etc
- 重點節錄:
When the Job's trigger fires (more on that in a moment), the execute(..) method is invoked by one of the scheduler's worker threads
- 將Trigger與Job分開建立的優勢:
- 可以定義好幾個不同的Trigger(執行時間),卻執行同一Job
- 使用JobKey and TriggerKey來管理你的Jobs與triggers,可用來進行分類管理,例如:Log用、維護用...etc
Quartz初體驗 - 如何使用不同的Schedule PropertySetting
在執行
scheduler.scheduleJob(job, trigger);
時出現:
RROR JobRunShell - Job group1.server.client.loginobserver.BackupGpBaseDataObser
ver@6909db threw an unhandled Exception:
java.lang.NullPointerException
at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.j
ava:557)
後來發現原來呼叫預設的
_scheduler = StdSchedulerFactory.getDefaultScheduler();
等同使用quartz.properties 此設定檔中的資料,
而每一個設定檔中的資料只能使用一次,因此若需建立第二個schedule,則需使用不同的設定檔:
- 建立新的properties設定檔:"backup.quartz.properties"
org.quartz.scheduler.instanceName = MyBackupScheduler org.quartz.threadPool.threadCount = 3 org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
- 將建立schedule code改為:
StdSchedulerFactory factory = new StdSchedulerFactory(); factory.initialize("backup.quartz.properties"); _scheduler = factory.getScheduler(); _scheduler.start();
StdSchedulerFactory factory = new StdSchedulerFactory(); factory.initialize();//default use quartz.properties _scheduler = factory.getScheduler(); _scheduler.start();
不過我搞不太懂為什麼問題出在【重複Schedule設定】,卻會拋出NullException這種這麼不明確的錯誤呢....
參考:Novice question: how do I get to PropertySettingFactory?
Quartz初體驗 - Job and Job Details
參考下列片段:
// define the job and tie it to our HelloJob class
JobDetail job = newJob(HelloJob.class)
.withIdentity("myJob", "group1") // name "myJob", group "group1"
.build();
// Trigger the job to run now, and then every 40 seconds
Trigger trigger = newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(40)
.repeatForever())
.build();
// Tell quartz to schedule the job using our trigger
sched.scheduleJob(job, trigger);
line 1~3說明了最簡單建立Job的方式,提供簡單的extend Job的Class!Job的建立生命週期如下:
- Shedule建立執行Job之前(call job's execute(..)),便為Job建立新的instance(如上述的HelloJob)
- Shedule call job's execute(..)
- job使用完畢,等待被GC回收
那麼,我們要怎麼樣在Job被execute之前指定特定資料呢?
使用JobDataMap
// define the job and tie it to our DumbJob class
JobDetail job = newJob(DumbJob.class)
.withIdentity("myJob", "group1") // name "myJob", group "group1"
.usingJobData("jobSays", "Hello World!")
.usingJobData("myFloatValue", 3.141f)
.build();
2.取得資料:
public class DumbJob implements Job {
public DumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
JobKey key = context.getJobDetail().getKey();
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
}
}
如上述範例,可先於創立JobDetail時指定資料,後於Job execute()時使用getJobDetail().getJobDataMap();取得所需資料。
然而需注意的是,置放於DataMap()的資料皆需為serialized
參考:Lesson 3: More About Jobs and Job Details
Quartz初體驗 - 從Job中自行關閉自己
- 於public void execute(JobExecutionContext arg0) throws JobExecutionException自行拋出JobExecutionException
- 將欲拋出的JobExecutionException設定為setUnscheduleAllTriggers(true)
- throw JobExecutionException
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
//do something...
try {
int zero = 0;
int calculation = 4815 / zero;
}
catch (Exception e) {
_log.info("--- Error in job!");
JobExecutionException e2 =
new JobExecutionException(e);
// Quartz will automatically unschedule
// all triggers associated with this job
// so that it does not run again
e2.setUnscheduleAllTriggers(true);
throw e2;
}
}
參考:Example - Dealing with Job Exceptions
訂閱:
文章 (Atom)