1. 程式人生 > >關於quartz定時任務實現Job介面無法註解為spring bean 的一種解決方案

關於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類的定時任務,實現統一排程或者動態排程。