關於quartz定時任務實現Job介面無法註解為spring bean 的一種解決方案
通常情況下,我們使用quartz之後,定時任務實現Job介面,並重寫execute()方法:
public class QuartzJob1 implements Job { /** * quartz回撥此介面,此介面中為定時任務具體執行內容 * * @param context * @throws JobExecutionException */ @Override public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("具體執行內容..."); } }
此種使用最困難的就是我們不可以注入其他spring物件.
本文提供的一種解決方案如下:
step1:
新建一個抽象類,實現Job介面,複寫execute()方法,同時另寫一個抽象方法,用於執行具體的定時任務內容,並交由子類實現,從而實現不同的定時任務呼叫不同的物件方法:
public abstract class ScheduleAbstractClassUtil implements Job { /** * 實現:將原來不可以注入的job改為可注入 * * 改寫原執行介面 -> 分發介面(從spring工廠根據類名拿取Job實現類) * 另寫執行內容介面,用spring工廠獲取的具體實現子類呼叫此介面 * @see this#exeTaskContent */ @Override public void execute(JobExecutionContext context) throws JobExecutionException { String domainName = ClassUtil.className2DomainName(this.getClass().getName()); // 從spring工廠根據類名拿取bean ScheduleAbstractClassUtil jobAbaUtil = SpringContextUtil.getBean(StringUtil.firstStr2LowerCase(domainName), this.getClass()); // 呼叫改寫後的具體執行內容介面 exeTaskContent jobAbaUtil.exeTaskContent(); } /** * 具體執行任務 */ public abstract void exeTaskContent(); }
execute()方法從spring工廠根據bean的名稱,動態獲取繼承了本類(ScheduleAbstractClassUtil)的定時任務子類,再呼叫exeTaskContent()方法,所以此方法相當於分發呼叫。
sep2:
關於SpringContextUtil:
@Component public class SpringContextUtil implements ApplicationContextAware { private static ApplicationContext context; @Override @SuppressWarnings("static-access" ) public void setApplicationContext(ApplicationContext contex) throws BeansException { // TODO Auto-generated method stub this.context = contex; } public static Object getBean(String beanName){ return context.getBean(beanName); } public static<T> T getBean(String beanName, Class<T> objClass){ T bean = (T) context.getBean(beanName); return bean; } }
step3:
每當我們有一個具體執行任務,由原來的實現Job介面,改為繼承ScheduleAbstractClassUtil抽象類,並實現exeTaskContent方法:
@Component
public class QuartzJob2 extends ScheduleAbstractClassUtil {
// 注入es客戶端物件
@Resource
private TransportClient transportClient;
@Override
public void exeTaskContent() {
SearchResponse searchResponse = transportClient.prepareSearch("index").setQuery(null).execute().actionGet();
System.out.println("查詢出的es資料量:" + searchResponse.getHits().getTotalHits());
}
}
將此Job註解為spring bean(@Compent),此時我們就可以隨心所欲注入其他物件啦!
step4:
呼叫流程:
quartz回撥實現了Job介面的execute()方法,由於定時任務類QuartzJob2繼承了ScheduleAbstractClassUtil類,並由他改寫execute()方法,在此方法中我們根據當前實現類QuartzJob2的類名從spring上下文獲取QuartzJob2例項,並呼叫其複寫ScheduleAbstractClassUtil類中的exeTaskContent()方法。
其他定時任務類由於類名不同,所以從spring上下文獲取到的bean不同,從而實現分發。
關於SpringContextUtil:
從spring上下文根據名稱獲取bean的時間是納秒級別,所以中小型系統無需擔心。
此外我們還可以根據掃描所有類,或者指定包下的繼承了ScheduleAbstractClassUtil類的定時任務,實現統一排程或者動態排程。