quartz定时任务之自定义注解实现动态配置任务

来源:互联网 发布:魔戒巫师知乎 编辑:程序博客网 时间:2024/05/30 19:35

项目需求:定时任务

实现方式?

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实现任务配置

编写执行代码:

@Componentpublic 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)@Documentedpublic @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 * 动态配置任务添加 *后期可以从数据库中配置任务,提供接口停止,重新安排,暂停任务等接口 */@Componentpublic 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,
实现任务对象的暂停,删除,重新安排等操作