日志:
Quartz使用SLF4J框架來滿足所有的日志記錄需求
SchedulerFactory
quartz中SchedulerFactory實現(xiàn)類:
org.quartz.impl.StdSchedulerFactory
org.quartz.impl.DirectSchedulerFactory
StdSchedulerFactory:
創(chuàng)建和初始化:
1.配置(java.util.Properties屬性完成->配置文件中加載)
2.程序創(chuàng)建并直接傳遞到工廠
DirectSchedulerFactory:
不支持配置完成初始化,程序編輯所有調(diào)度程序的設置畏线,要求用戶了解全過程(不支持)
Job
quartz中定義job都要實現(xiàn)org.quartz.Job接口静盅,并在execute方法中定義job的執(zhí)行流程
public class HelloJob implements Job{
private static Logger logger = LoggerFactory.getLogger(HelloJob.class);
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
logger.info("hello world!!!");
}
}
JobDetail
然而我們有時還需獲取job相關屬性,根據(jù)job屬性來定義執(zhí)行流程寝殴,此時我們則可以使用JobExecutionContext 對象來獲取蒿叠,如通過getJobDetail()來獲取預先定義的job屬性
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
logger.info("hello world!!!");
JobDetail jobDetail=jobExecutionContext.getJobDetail();
JobDataMap jobDataMap=jobDetail.getJobDataMap();
String name=jobDataMap.getString("name");
String sex=jobDataMap.getString("sex");
Double height=jobDataMap.getDouble("height");
//取出自定義對象
Hero hero=(Hero) jobDataMap.get("hero");
int age=jobDataMap.getIntValue("age");
logger.info("name:"+name+"\tsex:"+sex+"\tage:"+age+"\theight:"+height);
logger.info("hero:");
logger.info(hero.toString());
}
JobDataMap
在上面的案例中我們用到了JobDetail中的JobDataMap明垢,下面演示如何利用JobDataMap向jobExecutionContext傳遞參數(shù)
public static JobDetail defineJobDetailAndTieToRealJobClass(){
//存入JobDataMap(合并使用)
JobDataMap newJobDataMap=new JobDataMap();
newJobDataMap.put("name","關羽");
newJobDataMap.put("age",89);
newJobDataMap.put("height",2.8D);
//通過自己創(chuàng)建JobDataMap存入自定義對象
Hero hero=new Hero("張飛","男",45,1.89D);
newJobDataMap.put("hero",hero);
JobDetail job = newJob(HelloJob.class).withIdentity("job1", "group1")
.usingJobData("name","劉備")
.usingJobData("age",54)
.usingJobData("sex","男")
.usingJobData(newJobDataMap)//putAll合并JobDataMap
.build();
return job;
}
執(zhí)行結果:
[INFO] 26 五月 06:02:00.010 下午 DefaultQuartzScheduler_Worker-1 [com.feifei.test1.HelloJob]
hello world!!!
[INFO] 26 五月 06:02:00.012 下午 DefaultQuartzScheduler_Worker-1 [com.feifei.test1.HelloJob]
name:關羽 sex:男 age:89 height:2.8
[INFO] 26 五月 06:02:00.012 下午 DefaultQuartzScheduler_Worker-1 [com.feifei.test1.HelloJob]
hero:
[INFO] 26 五月 06:02:00.012 下午 DefaultQuartzScheduler_Worker-1 [com.feifei.test1.HelloJob]
Hero{name='張飛', sex='男', age=45, height=1.89}
自定義對象(考慮序列化問題實現(xiàn)Serializable接口):
public class Hero implements Serializable{
private String name;
private String sex;
private int age;
private Double height;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Double getHeight() {
return height;
}
public void setHeight(Double height) {
this.height = height;
}
public Hero() {
}
public Hero(String name, String sex, int age, Double height) {
this.name = name;
this.sex = sex;
this.age = age;
this.height = height;
}
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", height=" + height +
'}';
}
}
JobDataMap中可以包含不限量的(序列化的)數(shù)據(jù)對象,JobDataMap是Java Map接口的一個實現(xiàn)栈虚,只是額外增加了一些便于存取基本類型的數(shù)據(jù)的方法來減少存儲取出時的強制類型轉換袖外。如下:
putAsString(String,boolean):void
getIntValue(String):int
getDoubleValue(String):Double
getFloatValue(String):Float
getLongValue(String):Long
相關的方法還有很多,這里只是列舉出一部分魂务。
如果你在JobDataMap中存儲的都是java標準類型時并不用擔心什么曼验。
如果JobDataMap中存儲的有自定義對象,而你又恰好使用持久化的存儲機制粘姜,那么你就要注意了:
JobDataMap中存儲的對象都會被序列化鬓照,如果你已經(jīng)有了一個類序列化后的實例,在那之后有人改變了該類的定義孤紧,則有可能因破壞了兼容性而產(chǎn)生異常豺裆。
持久化的存儲機制(JobStore中說明)
簡單解決(如何配置以后說明):
配置JDBC-JobStore和JobDataMap只允許存儲基本類型和String類型的數(shù)據(jù)
經(jīng)過上面的學習我們已經(jīng)能夠向execute中傳遞和使用參數(shù)了,現(xiàn)在我們再思考一些細節(jié)問題:
我們可以通過JobDetail來設置job屬性号显,我們?yōu)槭裁床荒苤苯邮褂胘ob實現(xiàn)類的屬性呢臭猜,定義Job實現(xiàn)類時有什么要注意的呢?
scheduler在執(zhí)行job的execute(…)之前押蚤,首先會調(diào)用HelloJob的newInstance()創(chuàng)建一個新的實例蔑歌,調(diào)用完成后,HelloJob實例引用就被丟棄了揽碘,接著被垃圾回收次屠,可知
1.HelloJob必須有一個無參的構造函數(shù)(當使用默認的JobFactory時)雳刺;
〗僭睢2.job類中,不應該定義有狀態(tài)的數(shù)據(jù)屬性掖桦,因為在job的多次執(zhí)行中本昏,這些屬性的值不會保留。(每次執(zhí)行會重新創(chuàng)建一個HelloJob實例枪汪,之前定義的數(shù)據(jù)都會丟失)
我們已經(jīng)學會用JobDetail中的JobDataMap來存入和取出數(shù)據(jù)了涌穆,但每次都一個一個的根據(jù)key取出,有什么簡便方法嗎料饥?
使用JobFactory實現(xiàn)數(shù)據(jù)的自動注入是個不錯的選擇,他能讓你的excute()方法變的更加簡潔,只要在HelloJob中添加對應的自定義屬性和set方法即可朱监,JobFactory會幫你完成余下的工作的岸啡,HelloJob修改如下:
public class HelloJob implements Job{
private static Logger logger = LoggerFactory.getLogger(HelloJob.class);
private Hero hero;
public static Logger getLogger() {
return logger;
}
public static void setLogger(Logger logger) {
HelloJob.logger = logger;
}
public Hero getHero() {
return hero;
}
public void setHero(Hero hero) {
this.hero = hero;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Double getHeight() {
return height;
}
public void setHeight(Double height) {
this.height = height;
}
private String name;
private String sex;
private int age;
private Double height;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
logger.info("hello world!!!");
logger.info("name:"+name+"\tsex:"+sex+"\tage:"+age+"\theight:"+height);
logger.info("hero:");
logger.info(hero.toString());
}
}
相關注解:
@DisallowConcurrentExecution
位置:HelloJob類
作用范圍:JobDetail對象
作用效果:不允許JobDetail對象并發(fā)運行
@PersistJobDataAfterExecution
位置:HelloJob類
作用范圍:JobDetail對象
作用效果:成功執(zhí)行了job類的execute方法后(沒有發(fā)生任何異常),更新JobDetail中JobDataMap的數(shù)據(jù)赫编,jobDetail在下一次執(zhí)行時獲取到新的數(shù)據(jù).
JobDetail配置更多屬性:
Durability:如果一個job是非持久的巡蘸,當沒有活躍的trigger與之關聯(lián)的時候奋隶,會被自動地從scheduler中刪除。也就是說悦荒,非持久的job的生命期是由trigger的存在與否決定的唯欣;
RequestsRecovery:如果一個job是可恢復的,并且在其執(zhí)行的時候搬味,scheduler發(fā)生硬關閉(hard shutdown)(比如運行的進程崩潰了境氢,或者關機了),則當scheduler重新啟動的時候碰纬,該job會被重新執(zhí)行萍聊。此時,該job的JobExecutionContext.isRecovering() 返回true悦析。
JobExecutionException
細心的朋友應該已經(jīng)發(fā)現(xiàn)了Job.execute()方法上聲明了一個運行時異常->
JobExecutionException,Job通過該異常通知scheduler寿桨,這個異常攜帶著很多信息,你也許該花點時間看看JobExecutionException的文檔强戴,以便更好的處理此類異常亭螟。
下一篇我們開始Trigger,未完待續(xù)...