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

项目需求:定时任务

实现方式?

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,
实现任务对象的暂停,删除,重新安排等操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值