Spring-定时任务之Quartz

最近的项目中,使用了定时任务。网上搜索了很多关于定时任务的解决方案,大概总结一下有以下几种解决思路1java.util.Timer2Quartz3Spring3.0以后自带的task。本次项目解决方案采用的是Quartz来实现定时任务。

在 项目的过程中,期初需要的需求很简单(完成定时请求服务端的数据),采用了Quartz的配置方式,简单的配置后即可完成定时的任务,这算是静态定时任务。不久后,需要定时任务由用户自己配置,如配置任务执行周期、任务内容、开启/运行任务、添加/删除任务等,在网上寻找新的解决方法,最终选择采用了quartz的编程实现方式。

下面分别介绍这两种实现不同需求的定时任务的实现过程(原理性以后补充)。

方法一、配置实现

主要步骤:

a)在Spring.xml中,调度器里添加了两个触发器simpleTrigger和cronTrigger,前者是简单定时触发,后者采用了cron表达式。在类loopTask中,实现了两个定时触发器响应方法。

<bean id="loopTask" class="xxxxxx.MyLoopTask"/>
<bean id="loopCreateTable" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
   <property name="targetObject" ref="loopTask" />
   <property name="targetMethod" value="loopCreateDataTable" />
</bean>
<bean id="loopCreateTable" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
   <property name="targetObject" ref="loopTask" />
   <property name="targetMethod" value="loopCreateDataTable" />
</bean>
<bean id="loopOriginalData" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
   <property name="targetObject" ref="loopTask" />
   <property name="targetMethod" value="loopOriginalData" />
</bean>
<bean id="simpleTrigger"
     class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
   <property name="jobDetail" ref="loopOriginalData" />
   <property name="startDelay" value="10000" />
   <property name="repeatInterval" value="${httpconn1.period}" />
</bean>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
   <property name="jobDetail" ref="loopCreateTable" />
   <property name="cronExpression" value="0 0 * * * ?" />
</bean>

b)MyLookTask类,在该类中配置了服务类AService,可以在定时任务方法中使用(强调这个是因为在第二个动态定时任务中失效。)

public class MyLoopTask {
@Resource(name="AService")
private AService aservice;

public void loopCreateDataTable()
{
//使用aservice
}
public void loopOriginalData() {
//使用aservice

}


方法二、编码实现

编码实现,即在程序中实现动态定时任务,这里主要采用了几个工具类来完成定时任务:

MyJob类:实现了org.quartz.Job接口;

QuartUntils类:调度器工具类;

DutiesAgency类:在项目中,在定时任务调用的方法里无法使用服务类(由注解或配置注入的服务类),所以添加了一个代理任务,该代理任务包含了具体任务和被具体任务调用的服务。

具体实现类如下:

public class QuartzUntils {
    private Logger log = null;
    private Scheduler scheduler = null;
    public static final String DATA_KEY = "STATE_DATA";

    public QuartzUntils() {
        try {
            log = org.apache.logging.log4j.LogManager.getLogger();
            scheduler = new StdSchedulerFactory().getScheduler();
            log.info("初始化调度器 ");
        } catch (SchedulerException ex) {
            log.error("初始化调度器=> [失败]:" + ex.getLocalizedMessage());
        }
    }
    public void addJob(DutiesAgency da) {
        try {
            //构造任务
            JobDetail job = newJob(MyJob.class)
                    .withIdentity(da.getCrontabMangeEntity().getJobName(), da.getCrontabMangeEntity().getJobGroup())
                    .build();
            job.getJobDataMap().put("DutiesAgency",da);
            //构造任务触发器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(da.getCrontabMangeEntity().getCronExpression());
            Trigger trg = newTrigger()
                    .withIdentity(da.getCrontabMangeEntity().getJobName(), da.getCrontabMangeEntity().getJobName())
                    .withSchedule(scheduleBuilder)
                    .build();
            //将作业添加到调度器
            scheduler.scheduleJob(job, trg);
            log.info("创建作业=> [作业名称:" +da.getCrontabMangeEntity().getJobName() + " 作业组:" + da.getCrontabMangeEntity().getJobName() + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
               }
    }
    public void removeJob(String name, String group) {
        try {
            TriggerKey tk = TriggerKey.triggerKey(name, group);
            scheduler.pauseTrigger(tk);//停止触发器
            scheduler.unscheduleJob(tk);//移除触发器
            JobKey jobKey = JobKey.jobKey(name, group);
            scheduler.deleteJob(jobKey);//删除作业
            log.info("删除作业=> [作业名称:" + name + " 作业组:" + group + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("删除作业=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]");
        }
    }
    public void pauseJob(String name, String group) {
        try {
            JobKey jobKey = JobKey.jobKey(name, group);
            scheduler.pauseJob(jobKey);
            log.info("暂停作业=> [作业名称:" + name + " 作业组:" + group + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("暂停作业=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]");
        }
    }
    public void resumeJob(String name, String group) {
        try {
            JobKey jobKey = JobKey.jobKey(name, group);
            scheduler.resumeJob(jobKey);
            log.info("恢复作业=> [作业名称:" + name + " 作业组:" + group + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("恢复作业=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]");
        }
    }
    public void modifyTime(String name, String group, String cronExpression) {
        try {
            TriggerKey tk = TriggerKey.triggerKey(name, group);
            //构造任务触发器
            Trigger trg = newTrigger()
                    .withIdentity(name, group)
                    .withSchedule(cronSchedule(cronExpression))
                    .build();
            scheduler.rescheduleJob(tk, trg);
            log.info("修改作业触发时间=> [作业名称:" + name + " 作业组:" + group + "] ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("修改作业触发时间=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]");
        }
    }
    public void start() {
        try {
            scheduler.start();
            System.out.println("启动调度器");
            log.info("启动调度器 ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("启动调度器=> [失败]");
        }
    }
    public void shutdown() {
        try {
            scheduler.shutdown();
            log.info("停止调度器 ");
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("停止调度器=> [失败]");
        }
    }
    public static void main(String[] args) {
        QuartzUntils quartzUntils=new QuartzUntils();
        ScheduleJob job = new ScheduleJob();
        job.setJobId("10001");
        job.setJobName("data_import");
        job.setJobGroup("dataWork");
        job.setCronExpression("0/5 * * * * ?");
        quartzUntils.addJob(job);
        quartzUntils.start();*/
    }

public class MyJob implements Job {
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("定时任务开始...");
        DutiesAgency da = (DutiesAgency) context.getMergedJobDataMap().get("DutiesAgency");
        da.getOriginalDataService().dataDistribution(da.getCrontabMangeEntity());
    }
}


public class DutiesAgency {
    private CrontabMangeEntity crontabMangeEntity;
    private OriginalDataService originalDataService;
    public CrontabMangeEntity getCrontabMangeEntity() {
        return crontabMangeEntity;
    }
    private void setCrontabMangeEntity(CrontabMangeEntity crontabMangeEntity) {
        this.crontabMangeEntity = crontabMangeEntity;
    }
    public OriginalDataService getOriginalDataService() {
        return originalDataService;
    }
    private void setOriginalDataService(OriginalDataService originalDataService) {
        this.originalDataService = originalDataService;
    }
    public DutiesAgency(CrontabMangeEntity crontabMangeEntity,OriginalDataService originalDataService){
        this.crontabMangeEntity=crontabMangeEntity;
        this.originalDataService=originalDataService;
    }
}

在action里调用任务的添加任务,定时内容由前台配置,服务在action里注入,将定时内容和服务包装在代理里。

   quartzUntils.addJob(new DutiesAgency(crontabMangeEntity,originalDataService));

以上代码简单实现了动态可配置的定时任务。

本次动态的定时任务,为能够使用originalDataService,经过几番资料查询,请教大神,最终也只是实现了,但直觉上不是最佳的方式。以下几种方式均无法实现originalDataService服务;在execute中使用:至于为什么Spring注解失效,分别做了如下测试。

1)在每次MyJob类中execute方法调用时,其构造函数是执行的;

2)将一个Action类(项目采用了Spring+struts2框架)类实现Job接口,在action的execute定时执行时,该action的注解成员也均为null;

3)项目在加载时,originalDataService、MyJob以及originalDataService类的构造函数是执行的;

4在MyJob.execute的方法里直接实例化服务类,而在服务类中不使用注解/配置方式,能够实现,但和整个项目编码方式迥异,不爽。

部分代码如下:

@Resource(name="OriginalDataService")
private OriginalDataService originalDataService;//尝试1)采用注解,execute里调用为null

OriginalDataService originalDataService=new OriginalDataService();//尝试2)错

OriginalDataService originalDataService=new OriginalDataServiceImpl();//尝试3,可以实例化OriginalDataServiceImpl,但OriginalDataServiceImpl类中的注解成员为null,不行。
时间匆忙,有时间再研究学习关于定时任务,充实本帖,待续...

此外,真诚感谢以下博客提供宝贵的实现代码:

1、Spring定时任务的几种实现

2、Spring定时任务之quartz

3、Quartz2.x增删改查工具类

4、Quartz在Spring中如何动态配置时间

5、Spring3整合Quartz2实现定时任务二:动态添加任务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值