springboot下的quartz初学(使用cronTrigger并解决quartz下装配bean的问题)

最近用到了quartz,简单的整理一下quartz的知识点,并学习网上的知识来做了一个比较简单的例子

quartz简介
  • Scheduler - 与调度程序交互的主要API。
  • Job - 由希望由调度程序执行的组件实现的接口。
  • Trigger(即触发器) - 定义执行给定作业的计划的组件。

简单来说quartz就是由这三部分组成,我们首先定义job,即定时任务工作的内容,其次是trigger,即触发的时间,最后我们将前两者交给scheduler进行管理

quartz和springboot自带定时的区别

当使用springboot自带定时时,我选择将cron储存到数据库中,然后让定时任务访问数据库获得Trigger,但springboot有一个不足,那就是它只会在下次触发时间才会去访问数据库并通过数据库的cron来改变定时,想要实时改变异常困难.而quartz访问数据库的定时只会使用一次,也就是quartz启动的那一次,之后你改变数据库,并不会影响quartz,你只能调用quartz的方法来改变定时时间

quartz实例
SchedulerQuartzJob

此类为任务类,即本次定时任务我们要完成的功能,考虑到实际的情况,我在下面的例子中安排了三种场景:

  • 输出一句简单的话

  • 获得从前面传来的参数,并输出

  • 通过spring的依赖注入,获得一个service层或者mapper层的对象,用来操作数据库

    其中依赖注入因为quartz的原因不能成功,因此暂时注释掉,解决方案请往后看

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class SchedulerQuartzJob implements Job {
    //@Autowired
    //private MailJobMapper mailJobMapper;
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        
        JobDataMap dataMap = context.getJobDetail().getJobDataMap();
        String word = dataMap.getString("word"); //通过此我们可以获得前面传来的参数
        
        System.out.println("学习使用quartz"+word);
        //mailJobMapper.selsectByPrimaryKey(1);
    }
}
QuartzSchedulerNew

此类是最重要的类,我们定义job和trigger,并交给scheduler管理,并对外提供start,delete.modify等控制定时任务的方法

import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.Date;

@Component
@Configuration
public class QuartzSchedulerNew {
//    @Autowired
//    private MailJobMapper mailJobMapper;
    // 任务调度
    @Autowired
    private Scheduler scheduler;
    /**
     * 开始执行所有任务
     */
    public void startJob() throws SchedulerException {
        startJob(scheduler);
        scheduler.start();
    }
    /**
     * 获取Job信息
     */
    public String getJobInfo(String name, String group) throws SchedulerException {
        TriggerKey triggerKey = new TriggerKey(name, group);
        CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        return String.format("time:%s,state:%s", cronTrigger.getCronExpression(),
                scheduler.getTriggerState(triggerKey).name());
    }

    /**
     * 修改某个任务的执行时间
     */
    public boolean modifyJob(String name, String group, String time) throws SchedulerException {
        Date date = null;
        TriggerKey triggerKey = new TriggerKey(name, group);
        CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        String oldTime = cronTrigger.getCronExpression();
        if (!oldTime.equalsIgnoreCase(time)) {
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(time);
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group)
                    .withSchedule(cronScheduleBuilder).build();
            date = scheduler.rescheduleJob(triggerKey, trigger);
        }
        return date != null;
    }

    /**
     * 暂停所有任务
     */
    public void pauseAllJob() throws SchedulerException {
        scheduler.pauseAll();
    }

    /**
     * 暂停某个任务
     */
    public void pauseJob(String name, String group) throws SchedulerException {
        JobKey jobKey = new JobKey(name, group);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if (jobDetail == null)
            return;
        scheduler.pauseJob(jobKey);
    }

    /**
     * 恢复所有任务
     */
    public void resumeAllJob() throws SchedulerException {
        scheduler.resumeAll();
    }
    /**
     * 恢复某个任务
     */
    public void resumeJob(String name, String group) throws SchedulerException {
        JobKey jobKey = new JobKey(name, group);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if (jobDetail == null)
            return;
        scheduler.resumeJob(jobKey);
    }
    /**
     * 删除某个任务
     */
    public void deleteJob(String name, String group) throws SchedulerException {
        JobKey jobKey = new JobKey(name, group);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if (jobDetail == null)
            return;
        scheduler.deleteJob(jobKey);
    }
    private void startJob(Scheduler scheduler) throws SchedulerException {
            // 通过JobBuilder构建JobDetail实例,JobDetail规定只能是实现Job接口的实例
            // JobDetail 是具体Job实例
            JobDetail jobDetail = JobBuilder
                    .newJob(SchedulerQuartzJob.class)
                    .withIdentity("job1", "group1")
                    .usingJobData("word", "Hello,World")//可以往ScheduleQuartzJob传参
                    .build();
            // 基于表达式构建触发器
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0 1 * * * ?");//mailJob.getCron()
            // CronTrigger表达式触发器 继承于Trigger
            // TriggerBuilder 用于构建触发器实例
            CronTrigger cronTrigger = TriggerBuilder
                    .newTrigger()
                    .withIdentity("job1", "group1")
                    .withSchedule(cronScheduleBuilder)
                    .build();
            scheduler.scheduleJob(jobDetail, cronTrigger);
        }
    }
ApplicationStartQuartzJobListener

此类的作用为监听spring,是我们在任务一启动就可以开启定时任务

import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Configuration
@Component
public class ApplicationStartQuartzJobListener implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    private QuartzSchedulerNew quartzSchedulerNew;
    /**
     * 初始启动quartz
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        try {
            quartzSchedulerNew.startJob();
            System.out.println("quartz初始化中.......");
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
    /**
     * 初始注入scheduler
     * @return
     * @throws SchedulerException
     */
    @Bean
    public Scheduler scheduler() throws SchedulerException{
        SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();
        return schedulerFactoryBean.getScheduler();
    }

}

QuartzApiController

我们对外提供url,调用定时任务的各个方法,这样就能让我们实时控制我们的定时任务

@RestController
@RequestMapping("/quartz")
public class QuartzApiController {
    @Autowired
    private QuartzSchedulerNew quartzSchedulerNew;

    @RequestMapping("/start")
    public void startQuartzJob() {
        try {
            quartzSchedulerNew.startJob();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
    @RequestMapping("/info")
    public String getQuartzJob(String name, String group) {
        String info = null;
        try {
            info = quartzSchedulerNew.getJobInfo(name, group);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return info;
    }
    @RequestMapping("/modify")
    public boolean modifyQuartzJob(String name, String group, String time) {
        boolean flag = true;
        try {
            flag = quartzSchedulerNew.modifyJob(name, group, time);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return flag;
    }
    @RequestMapping(value = "/pause")
    public void pauseQuartzJob(String name, String group) {
        try {
            quartzSchedulerNew.pauseJob(name, group);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
    @RequestMapping(value = "/pauseAll")
    public void pauseAllQuartzJob() {
        try {
            quartzSchedulerNew.pauseAllJob();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
    @RequestMapping(value="/resumeAll")
    public void resume(){
        try {
            quartzSchedulerNew.resumeAllJob();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
    @RequestMapping(value = "/delete")
    public void deleteJob(String name, String group) {
        try {
            quartzSchedulerNew.deleteJob(name, group);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}
解决springboot不能在quartz注入bean的问题

我们想在quartz中的job中做出一些其他操作,尤其是操作数据库的操作,但当我们注入service对象运行时,却发现出现问题,以下就是我们的解决方式:

JobFactory
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

@Component
public class JobFactory extends AdaptableJobFactory {
    /**
     * AutowireCapableBeanFactory接口是BeanFactory的子类
     * 可以连接和填充那些生命周期不被Spring管理的已存在的bean实例
     */
    private AutowireCapableBeanFactory factory;
    public JobFactory(AutowireCapableBeanFactory factory) {
        this.factory = factory;
    }
    /**
     * 创建Job实例
     */
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        // 实例化对象
        Object job = super.createJobInstance(bundle);
        // 进行注入(Spring管理该Bean)
        factory.autowireBean(job);
        //返回对象
        return job;
    }
}
QuartzConfig
import org.quartz.Scheduler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

@Configuration
public class QuartzConfig {
    private JobFactory jobFactory;

    public QuartzConfig(JobFactory jobFactory){
        this.jobFactory = jobFactory;
    }
    /**
     * 配置SchedulerFactoryBean
     * 将一个方法产生为Bean并交给Spring容器管理
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        // Spring提供SchedulerFactoryBean为Scheduler提供配置信息,并被Spring容器管理其生命周期
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        // 设置自定义Job Factory,用于Spring管理Job bean
        factory.setJobFactory(jobFactory);
        return factory;
    }
    @Bean(name = "scheduler")
    public Scheduler scheduler() {
        return schedulerFactoryBean().getScheduler();
    }
}

最后我们在配置文件里加入下面这句话

spring.main.allow-bean-definition-overriding=true
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值