项目需求:定时任务
实现方式?
spring自带定时任务,jdk自带Timer,quartz实现。
优缺点,spring,基于注解实现,配置简单,但是后期任务丰富,之后,修改配置较为困难,且不容易控制
jdk自带,实现简单,不便于控制,
quartz,功能强大,可配置。
所以为了以后项目的扩展,果断采用quartz,引入quartz jar包,
quartz-2.2.3.jar quartz-jobs-2.2.3.jar
spring 4.0
quartz实现任务配置
编写执行代码:
@Component
public class TestJob {
public void exe(){
System.out.println("hello test");
}
}
<!--定义jobdetail-->
<bean id="testTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="testJob "/>
<property name="targetMethod" value="exe"/>
</bean>
<!--定义触发器-->
<bean id="handletrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="testTask"/>
<property name="cronExpression" value="${handle_cron}"/>
</bean>
以上操作,每次
<!--定义调度器-->
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="testtrigger"/>
<ref bean="testtrigger1"/>
<ref bean="testtrigger2"/>
</list>
</property>
<property name="autoStartup" value="true"/>
</bean>
每次新增一个调度任务,都需要在xml里添加这些配置,真心麻烦
减少配置
1.分析
为了减少xml的配置,我们可以观察一下,spring项目中,启动一个任务的配置顺序,不难发现,
org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean和org.springframework.scheduling.quartz.CronTriggerFactoryBean
是实例化一个任务对象的java对象,都是spring对quartz的封装,
其次是org.springframework.scheduling.quartz.SchedulerFactoryBean
调度器,实现对上一步任务对象的调度
所以我们要减少配置,就要从SchedulerFactoryBean入手,重写SchedulerFactoryBean,使他能够自动注册任务对象,这其中用到了自定义注解
2.代码实现
自定义注解
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Job {
//定时任务分组
String group() default "default";
//执行任务方法
String executeMethod() default "execute";
//执行任务表达式,可支持${}表达式,默认从config/job.properties加载配置cron表达式
String cron() default "";
}
重写的任务调度器SchedulerFactoryBean,实现自动装配任务
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.quartz.JobKey;
import org.quartz.Trigger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
/**
*
* @author ll
* 动态配置任务添加
*后期可以从数据库中配置任务,提供接口停止,重新安排,暂停任务等接口
*/
@Component
public class EcrDynamicScheduler extends SchedulerFactoryBean implements ApplicationContextAware {
private static ApplicationContext applicationContext;
//默认配置文件地址
private static final String DEFAULT_CONFIG_PATH="config/job.properties";
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
init();
}
private void init(){
//获取自定义注解bean对象
Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(Job.class);
if(beansWithAnnotation!=null){
try {
Collection<Object> values = beansWithAnnotation.values();
MethodInvokingJobDetailFactoryBean jobBean=null;
CronTriggerFactoryBean triggerBean=null;
List<Trigger> triggerBeans=new ArrayList<Trigger>();
//读取默认cron表达式配置文件
Properties properties=PropertiesUtils.getProperties(DEFAULT_CONFIG_PATH);
for(Object targetObject:values){
//创建jobbean
jobBean=new MethodInvokingJobDetailFactoryBean();
//获取bean上的注解
Job jobAnno = targetObject.getClass().getAnnotation(Job.class);
//获取注解内容
String group = jobAnno.group();
String executeMethod = jobAnno.executeMethod();
String beanName=targetObject.getClass().getSimpleName();
String cron=jobAnno.cron();
if(cron.contains("${")){//如果cron是el表达式,则从配置文件中获取
cron=properties.getProperty(cron.substring(2, cron.indexOf("}")), "");
}
jobBean.setTargetObject(targetObject);
jobBean.setGroup(group);
jobBean.setTargetMethod(executeMethod);
jobBean.setBeanName(beanName+"_jobBean");
//jobkey:group.beanName.executeMethod
jobBean.setName(beanName+"."+executeMethod);
jobBean.afterPropertiesSet();
//创建触发器
triggerBean=new CronTriggerFactoryBean();
triggerBean.setJobDetail(jobBean.getObject());
triggerBean.setCronExpression(cron);
triggerBean.setBeanName(beanName+"_triggerBean");
triggerBean.setName(beanName+"."+executeMethod);
triggerBean.afterPropertiesSet();
triggerBeans.add(triggerBean.getObject());
}
Trigger[] triggers = triggerBeans.toArray(new Trigger[triggerBeans.size()]);
//交给执行器执行
setAutoStartup(true);
setTriggers(triggers);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
这个重写的SchedulerFactoryBean比较简单,也是因为项目需求也比较简单,所以就没有写太多功能,其实还有很多可以扩充的地方,可以保存任务对象jobkey和jobdetail,
实现任务对象的暂停,删除,重新安排等操作