通常情况下,我们使用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类的定时任务,实现统一调度或者动态调度。