SpringBoot集成Quartz动态定时任务(解决quartz的job无法注入spring对象的问题)

 目录

为什么要使用Quartz

1,添加Maven依赖

2,任务工厂JobFactory

3,新建一个QuartzConfig

4,新建一个QuartzScheduler

5,监听器QuartzJobListener 

6,自定义定时任务类MyJob 


Spring Boot 整合 Quartz 实现定时任务 

为什么要使用Quartz

多任务情况下,quartz更容易管理,可以实现动态配置 
执行时间表达式: 

SpringBoot集成Quartz动态定时任务(解决quartz的job无法注入spring对象的问题)_第1张图片

 表达式示例: 

SpringBoot集成Quartz动态定时任务(解决quartz的job无法注入spring对象的问题)_第2张图片

1,添加Maven依赖



    org.quartz-scheduler
    quartz
    2.2.1

2,任务工厂JobFactory

这里我们需要注意 我注入了一个 自定义的JobFactory ,然后 把其设置为SchedulerFactoryBean 的 JobFactory。其目的是因为我在具体的Job 中 需要Spring 注入一些Service。
所以我们要自定义一个jobfactory, 让其在具体job 类实例化时 使用Spring 的API 来进行依赖注入。

JobFactory具体实现:

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

/**
 * @Author: liangbl
 * @Date: 2019/1/22 11:06
 * @Description: 任务工厂JobFactory
 * 解决SpringBoot不能在Quartz中注入Bean的问题
 */
@Component
public class JobFactory extends AdaptableJobFactory {
    /**
     * AutowireCapableBeanFactory接口是BeanFactory的子类,可以连接和填充那些生命周期不被Spring管理的已存在的bean实例
     */
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    /**
     * 创建Job实例
     * @param bundle
     * @return
     * @throws Exception
     */
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        // 实例化对象
        Object jobInstance = super.createJobInstance(bundle);
        // 进行注入(Spring管理该Bean)
        capableBeanFactory.autowireBean(jobInstance);
        //返回对象
        return jobInstance;
    }
}

3,新建一个QuartzConfig

添加 QuartzConfig 类 来声明相关Bean

import org.quartz.Scheduler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

/**
 * @Author: liangbl
 * @Date: 2019/1/22 11:06
 * @Description: 任务调度器 Scheduler
 */
@Configuration
public class QuartzConfig {

    private JobFactory jobFactory;

    public QuartzConfig(JobFactory jobFactory){
        this.jobFactory = jobFactory;
    }

    /**
     * 配置SchedulerFactoryBean
     * 将一个方法产生为Bean并交给Spring容器管理
     * @return
     */
    @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();
    }
}

4,新建一个QuartzScheduler

在其他类中调用本类中的addJob方法进行任务添加

import com.hellowin.b2c.base.SSHValidateHelper;
import com.hellowin.b2c.persistence.model.cron.CronTask;
import org.apache.log4j.Logger;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @Author: liangbl
 * @Date: 2019/1/21 13:51
 * @Description: 任务调度处理
 */
@Service
public class QuartzScheduler {
    public final Logger log = Logger.getLogger(this.getClass());
    /**
     * 任务调度
     */
    @Autowired
    private Scheduler scheduler;

    /**
     * 开始执行所有任务
     *
     * @throws SchedulerException
     */
    public void startJob() throws SchedulerException {
        startJob(scheduler);
    }

    /**
     * 获取Job信息
     *
     * @param name
     * @param group
     * @return
     * @throws SchedulerException
     */
    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());
    }

    /**
     * 修改某个任务的执行时间
     *
     * @param name
     * @param group
     * @param time
     * @return
     * @throws SchedulerException
     */
    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;
    }

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

    /**
     * 暂停某个任务
     *
     * @param name
     * @param group
     * @throws SchedulerException
     */
    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);
    }

    /**
     * 恢复所有任务
     *
     * @throws SchedulerException
     */
    public void resumeAllJob() throws SchedulerException {
        scheduler.resumeAll();
    }

    /**
     * 恢复某个任务
     *
     * @param name
     * @param group
     * @throws SchedulerException
     */
    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);
    }

    /**
     * 删除某个任务
     *
     * @param name
     * @param group
     * @throws SchedulerException
     */
    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);
    }

    /**
     * 修改一个任务的触发时间
     *
     * @param triggerName      触发器名
     * @param triggerGroupName 触发器组名
     * @param cron             时间设置,参考quartz说明文档
     */
    public void modifyJobTime(String triggerName, String triggerGroupName, String cron) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (trigger == null) {
                return;
            }
            String oldTime = trigger.getCronExpression();
            if (!oldTime.equalsIgnoreCase(cron)) {
                // 触发器
                TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();
                // 触发器名,触发器组
                triggerBuilder.withIdentity(triggerName, triggerGroupName);
                triggerBuilder.startNow();
                // 触发器时间设定
                triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
                // 创建Trigger对象
                trigger = (CronTrigger) triggerBuilder.build();
                // 方式一 :修改一个任务的触发时间
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 移除一个任务
     *
     * @param jobName          任务名
     * @param jobGroupName     任务组名
     * @param triggerName      触发器名
     * @param triggerGroupName 触发器组名
     */
    public void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
            // 停止触发器
            scheduler.pauseTrigger(triggerKey);
            // 移除触发器
            scheduler.unscheduleJob(triggerKey);
            // 删除任务
            scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取任务是否存在
     * 

* STATE_BLOCKED 4 阻塞 * STATE_COMPLETE 2 完成 * STATE_ERROR 3 错误 * STATE_NONE -1 不存在 * STATE_NORMAL 0 正常 * STATE_PAUSED 1 暂停 */ public Boolean notExists(String triggerName, String triggerGroupName) { try { return scheduler.getTriggerState(TriggerKey.triggerKey(triggerName, triggerGroupName)) == Trigger.TriggerState.NONE; } catch (Exception e) { throw new RuntimeException(e); } } private void startJob(Scheduler scheduler) throws SchedulerException { // 通过JobBuilder构建JobDetail实例,JobDetail规定只能是实现Job接口的实例 // JobDetail 是具体Job实例 JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("job1", "group1").build(); // 基于表达式构建触发器 CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?"); // CronTrigger表达式触发器 继承于Trigger // TriggerBuilder 用于构建触发器实例 CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("job1", "group1") .withSchedule(cronScheduleBuilder).build(); scheduler.scheduleJob(jobDetail, cronTrigger); // 启动 if (!scheduler.isShutdown()) { scheduler.start(); } } /** * 添加一个定时任务 * * @param jobName 任务名 * @param jobGroupName 任务组名 * @param triggerName 触发器名 * @param triggerGroupName 触发器组名 * @param jobClass 任务 * @param cron 时间设置,参考quartz说明文档 */ public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, String jobClass, String cron, Map params) { try { Class aClass = (Class) Class.forName(jobClass).newInstance().getClass(); // 任务名,任务组,任务执行类 JobDetail job = JobBuilder.newJob(aClass).withIdentity(jobName, jobGroupName).build(); // 任务参数 job.getJobDataMap().putAll(params); // 触发器 TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger(); // 触发器名,触发器组 triggerBuilder.withIdentity(triggerName, triggerGroupName); triggerBuilder.startNow(); // 触发器时间设定 triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron)); // 创建Trigger对象 CronTrigger trigger = (CronTrigger) triggerBuilder.build(); // 调度容器设置JobDetail和Trigger scheduler.scheduleJob(job, trigger); // 启动 if (!scheduler.isShutdown()) { scheduler.start(); } } catch (Exception e) { throw new RuntimeException(e); } } // 以下方法把参数封装成了对象,方便传参 /** * 添加一个定时任务 * @param task */ public void addJob(CronTask task) { try { // 创建jobDetail实例,绑定Job实现类 // 指明job的名称,所在组的名称,以及绑定job类 Class jobClass = (Class) (Class.forName(task.getBeanClass()).newInstance().getClass()); // 任务名称和组构成任务key JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(task.getJobName(), task.getTypeName()) //参数 .usingJobData("parameter", task.getParameter()) .build(); //判断map参数是否有值 if (SSHValidateHelper.isNotEmptyMap(task.getParameterMap())) { Set set = task.getParameterMap().keySet(); if (SSHValidateHelper.isNotEmptyCollection(task.getParameterMap().keySet())) { for (String key : set) { jobDetail.getJobDataMap().put(key, task.getParameterMap().get(key)); } } } // 定义调度触发规则、使用cornTrigger规则、触发器key Trigger trigger = TriggerBuilder.newTrigger().withIdentity(task.getJobName(), task.getTypeName()).startAt(DateBuilder.futureDate(1, DateBuilder.IntervalUnit.SECOND)) .withSchedule(CronScheduleBuilder.cronSchedule(task.getCronExpression())).startNow().build(); // 把作业和触发器注册到任务调度中 scheduler.scheduleJob(jobDetail, trigger); // 启动 if (!scheduler.isShutdown()) { scheduler.start(); } } catch (Exception e) { e.printStackTrace(); } } /** * 获取所有计划中的任务列表 * * @return * @throws SchedulerException */ public List getAllJob() throws SchedulerException { GroupMatcher matcher = GroupMatcher.anyJobGroup(); Set jobKeys = scheduler.getJobKeys(matcher); List jobList = new ArrayList(); for (JobKey jobKey : jobKeys) { List triggers = scheduler.getTriggersOfJob(jobKey); for (Trigger trigger : triggers) { CronTask job = new CronTask(); job.setJobName(jobKey.getName()); job.setTypeName(jobKey.getGroup()); job.setDescription("触发器:" + trigger.getKey()); Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey()); job.setTypeName(triggerState.name()); if (trigger instanceof CronTrigger) { CronTrigger cronTrigger = (CronTrigger) trigger; String cronExpression = cronTrigger.getCronExpression(); job.setCronExpression(cronExpression); } jobList.add(job); } } return jobList; } /** * 所有正在运行的job * * @return * @throws SchedulerException */ public List getRunningJob() throws SchedulerException { List executingJobs = scheduler.getCurrentlyExecutingJobs(); List jobList = new ArrayList(executingJobs.size()); for (JobExecutionContext executingJob : executingJobs) { CronTask job = new CronTask(); JobDetail jobDetail = executingJob.getJobDetail(); JobKey jobKey = jobDetail.getKey(); Trigger trigger = executingJob.getTrigger(); job.setJobName(jobKey.getName()); job.setTypeName(jobKey.getGroup()); job.setDescription("触发器:" + trigger.getKey()); Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey()); job.setJobStatus(Long.parseLong(triggerState.name())); if (trigger instanceof CronTrigger) { CronTrigger cronTrigger = (CronTrigger) trigger; String cronExpression = cronTrigger.getCronExpression(); job.setCronExpression(cronExpression); } jobList.add(job); } return jobList; } /** * 暂停一个job * * @param task * @throws SchedulerException */ public void pauseJob(CronTask task) throws SchedulerException { JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getTypeName()); scheduler.pauseJob(jobKey); } /** * 恢复一个job * * @param task * @throws SchedulerException */ public void resumeJob(CronTask task) throws SchedulerException { JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getTypeName()); scheduler.resumeJob(jobKey); } /** * 删除一个job * * @param task * @throws SchedulerException */ public void deleteJob(CronTask task) throws SchedulerException { JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getTypeName()); scheduler.deleteJob(jobKey); } /** * 立即执行job * * @param task * @throws SchedulerException */ public void runJobNow(CronTask task) throws SchedulerException { JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getTypeName()); scheduler.triggerJob(jobKey); } /** * 更新job时间表达式 * * @param task * @throws SchedulerException */ public void updateJobCron(CronTask task) throws SchedulerException { TriggerKey triggerKey = TriggerKey.triggerKey(task.getJobName(), task.getTypeName()); CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCronExpression()); trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); scheduler.rescheduleJob(triggerKey, trigger); } }

实体类CronTask属性如下:

public class CronTask {
    /** 任务名称 */
    private String jobName;

    /** 参数 */
    private String parameter;

    /** 任务分组 1:   2: */
    private Long type;

    /** 任务分组名 */
    private String typeName;

    /** 调度规则:0/5 * * * * ? */
    private String cronExpression;

    /**  任务执行时调用哪个类的方法 包名+类名 */
    private String beanClass;

    /** 任务描述 */
    private String description;

    /**  任务状态 */
    private Long jobStatus;

    /** 0 未删除   1 删除 */
    private Long deleteFlag;

    /**参数的map*/
    @Transient
    private Map parameterMap;
}

5,监听器QuartzJobListener 

自定义一个监听类,Quartz的job在项目重启时,job都失效了,把每次启动的job都存放在数据库,然后项目启动时监听器读取数据库的job,然后添加job。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: liangbl
 * @Date: 2019/1/21 14:29
 * @Description: 监听器
 * Quartz的job在项目重启时,job都失效了,把每次启动的job都存放在数据库,然后项目启动时监听器读取数据库的job,然后添加job
 */
@Component
@Order(value = 1)
public class QuartzJobListener implements CommandLineRunner {
    @Autowired
    private QuartzScheduler quartzScheduler;

    /**
     * 初始启动quartz
     * @param
     */
    @Override
    public void run(String... args) throws Exception {
        try {
            // quartzScheduler.startJob();

            // 此处就不写获取数据库了,模拟一个集合遍历的数据
            List> listMap=new ArrayList<>();
            Map map1= new HashMap<>(16);
            map1.put("jobClass","com.hellowin.b2c.quartz.MyJob");
            map1.put("jobName","job1");
            map1.put("jobGroupName","job1");
            map1.put("jobTime","0/5 * * * * ? ");
            listMap.add(map1);
            for (Map map : listMap) {
                try {
                    quartzScheduler.addJob((String)map.get("jobName"),(String)map.get("jobGroupName"), (String)map.get("jobName"),(String)map.get("jobGroupName"),(String)map1.get("jobClass"),(String)map.get("jobTime"),new HashMap<>(16));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            System.out.println("任务已经启动...");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

6,自定义定时任务类MyJob 

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

import java.text.SimpleDateFormat;

/**
 * @Author: liangbl
 * @Date: 2019/1/21 13:46
 * @Description: 自定义定时任务类
 */
public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String jobName = jobExecutionContext.getJobDetail().getKey().toString();
        System.out.println(jobName + "任务开始执行:" + dateformat.format(System.currentTimeMillis()));
        // TODO 业务job1.job1
        System.out.println(jobName + "任务执行完成:" + dateformat.format(System.currentTimeMillis()));
    }
}

你可能感兴趣的:(Java)