Quartz使用总结

Quartz框架简介

Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目

Quartz核心概念

Scheduler:任务调度器,是实际执行任务调度的控制器。

Trigger:触发器,用于定义任务调度的时间规则,有SimpleTrigger,CronTrigger,DateIntervalTrigger和NthIncludedDayTrigger,其中CronTrigger用的比较多,本文主要介绍这种方式。CronTrigger在spring中封装在CronTriggerFactoryBean中。

Calendar:它是一些日历特定时间点的集合。一个trigger可以包含多个Calendar,以便排除或包含某些时间点。

JobDetail:用来描述Job实现类及其它相关的静态信息,如Job名字、关联监听器等信息。

Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中。

Cron表达式

cron表达式格式:

{秒数} {分钟} {小时} {日期} {月份} {星期}{年份(可为空)}
例 “0 0 12 ? * WED” 在每星期三下午12:00 执行(年份通常 省略)

每个字段的允许值

字段 允许值 允许的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小时 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 或者 JAN-DEC , - * /
星期 1-7 或者 SUN-SAT , - * ? / L C #
年(可选) 留空, 1970-2099 , - * /

值的含义

Seconds (秒) :可以用数字0-59 表示,
Minutes(分) :可以用数字0-59 表示,
Hours(时) :可以用数字0-23表示,
Day-of-Month(天) :可以用数字1-31 中的任一一个值,但要注意一些特别的月份
Month(月) :可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
Day-of-Week(每周):可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示

Spring Boot整合Quartz

1、添加依赖

<dependency>
 <groupId>org.quartz-scheduler</groupId>
 <artifactId>quartz</artifactId>
 <version>2.2.3</version>
</dependency>
<dependency>
 <groupId>org.quartz-scheduler</groupId>
 <artifactId>quartz-jobs</artifactId>
 <version>2.2.3</version>

2、在maven项目的resource目录下创建quartz.properties

org.quartz.scheduler.instanceName = MyScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false

#线程池配置
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

#持久化配置
org.quartz.jobStore.misfireThreshold = 50000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#支持集群
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.useProperties = true
org.quartz.jobStore.clusterCheckinInterval = 15000
#使用weblogic连接Oracle驱动
#org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.weblogic.WebLogicOracleDelegate
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = qzDS
#数据源连接信息,quartz默认使用c3p0数据源可以被自定义数据源覆盖
org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL = jdbc:mysql://XXXX:XXX/XXXXX?useUnicode=true&characterEncoding=utf-8
org.quartz.dataSource.qzDS.user = XXX
org.quartz.dataSource.qzDS.password = XXX
org.quartz.dataSource.qzDS.maxConnections = 10

3、quartz官网下载对应版本的quartz,解压打开docs/dbTables里面有不同数据库的建表语句,在使用quartz做持久化的时候需要用到这些表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oy2EndYb-1592549360412)(http://dwiki.cmbchina.cn/download/attachments/71968334/image2019-9-20_13-10-19.png?version=1&modificationDate=1568956220000&api=v2)]

4、添加配置类,这里创建job 实例工厂,解决spring注入问题,如果使用默认会导致spring的@Autowired 无法注入问题

public class SchedulerConfig implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
 private JobFactory jobFactory;

 @Override
 public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("任务已经启动..."+event.getSource());
 }

    @Bean(name = "dataSourceQuartz")
    @ConfigurationProperties(prefix = "kb.database")
    public DataSource dataSource(){
        DataSource dataSource = DruidDataSourceBuilder.create().build();
 return dataSource;
 }

    @Bean
 public SchedulerFactoryBean schedulerFactoryBean(@Autowired DataSource dataSource ) throws IOException {
        //获取配置属性
 PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
 propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
 //在quartz.properties中的属性被读取并注入后再初始化对象
 propertiesFactoryBean.afterPropertiesSet();
 //创建SchedulerFactoryBean
 SchedulerFactoryBean factory = new SchedulerFactoryBean();
 factory.setQuartzProperties(propertiesFactoryBean.getObject());
 //使用数据源,自定义数据源
 factory.setDataSource(dataSource);
 factory.setJobFactory(jobFactory);
 factory.setWaitForJobsToCompleteOnShutdown(true);//这样当spring关闭时,会等待所有已经启动的quartz job结束后spring才能完全shutdown。
 factory.setOverwriteExistingJobs(false);
 factory.setStartupDelay(1);
 return factory;
 }

    /* * 通过SchedulerFactoryBean获取Scheduler的实例 */
 @Bean(name="scheduler")
    public Scheduler scheduler(@Autowired DataSource dataSource) throws IOException {
        return schedulerFactoryBean(dataSource).getScheduler();
 }


    @Bean
 public QuartzInitializerListener executorListener() {
        return new QuartzInitializerListener();
 }
}

5、定义JobDetail

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
@Component
public class SyncJob implements Job {
    @Autowired
 Question2DAO question2DAO;

 @Override
 public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap data=context.getTrigger().getJobDataMap();
 String invokeParam =(String) data.get("invokeParam");
 System.out.println("job one param : " + invokeParam + " : " + new Date());
 //在这里实现业务逻辑
 try{
            List<ESQuestionModel> list = question2DAO.getUpdatedQuestions(0L);
 System.out.println(list);
 }catch (Exception e){
            e.printStackTrace();
 }
    }
}

6、对定时任务进行管理

@Service
public class QuartzServiceImpl implements QuartzService {

    @Autowired
    @Qualifier("scheduler")
    private Scheduler scheduler;

    /**
     * 新建一个任务
     */
    @Override
    public String addJob(AppQuartz appQuartz) throws Exception {

        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = df.parse(appQuartz.getStartTime());

        if (!CronExpression.isValidExpression(appQuartz.getCronExpression())) {
            return "Illegal cron expression"; //表达式格式不正确
        }
        JobDetail jobDetail = null;
        //构建job信息
        if ("JobOne".equals(appQuartz.getJobGroup())) {
            jobDetail = JobBuilder.newJob(SyncJob.class).withIdentity(appQuartz.getJobName(), appQuartz.getJobGroup()).build();
        }
        if ("JobTwo".equals(appQuartz.getJobGroup())) {
            jobDetail = JobBuilder.newJob(JobTwo.class).withIdentity(appQuartz.getJobName(), appQuartz.getJobGroup()).build();
        }

        //表达式调度构建器(即任务执行的时间,不立即执行)
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(appQuartz.getCronExpression()).withMisfireHandlingInstructionDoNothing();

        //按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(appQuartz.getJobName(), appQuartz.getJobGroup()).startAt(date)
                .withSchedule(scheduleBuilder).build();

        //传递参数
        if (appQuartz.getInvokeParam() != null && !"".equals(appQuartz.getInvokeParam())) {
            trigger.getJobDataMap().put("invokeParam", appQuartz.getInvokeParam());
        }
        scheduler.scheduleJob(jobDetail, trigger);
        // pauseJob(appQuartz.getJobName(),appQuartz.getJobGroup());
        return "success";
    }

    /**
     * 获取Job状态 * @param jobName * @param jobGroup * @return * @throws SchedulerException
     */
    public String getJobState(String jobName, String jobGroup) throws SchedulerException {
        TriggerKey triggerKey = new TriggerKey(jobName, jobGroup);
        return scheduler.getTriggerState(triggerKey).name();
    }

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

    //暂停任务
    @Override
    public String pauseJob(String jobName, String jobGroup) throws SchedulerException {
        JobKey jobKey = new JobKey(jobName, jobGroup);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if (jobDetail == null) {
            return "fail";
        } else {
            scheduler.pauseJob(jobKey);
            return "success";
        }
    }

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

    // 恢复某个任务
    @Override
    public String resumeJob(String jobName, String jobGroup) throws SchedulerException {
        JobKey jobKey = new JobKey(jobName, jobGroup);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if (jobDetail == null) {
            return "fail";
        } else {
            scheduler.resumeJob(jobKey);
            return "success";
        }
    }

    //删除某个任务
    @Override
    public String deleteJob(AppQuartz appQuartz) throws SchedulerException {
        JobKey jobKey = new JobKey(appQuartz.getJobName(), appQuartz.getJobGroup());
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if (jobDetail == null) {
            return "jobDetail is null";
        } else if (!scheduler.checkExists(jobKey)) {
            return "jobKey is not exists";
        } else {
            scheduler.deleteJob(jobKey);
            return "success";
        }
    }

    //修改任务
    @Override
    public String modifyJob(AppQuartz appQuartz) throws SchedulerException {
        if (!CronExpression.isValidExpression(appQuartz.getCronExpression())) {
            return "Illegal cron expression";
        }
        TriggerKey triggerKey = TriggerKey.triggerKey(appQuartz.getJobName(), appQuartz.getJobGroup());
        JobKey jobKey = new JobKey(appQuartz.getJobName(), appQuartz.getJobGroup());
        if (scheduler.checkExists(jobKey) && scheduler.checkExists(triggerKey)) {
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            //表达式调度构建器,不立即执行
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(appQuartz.getCronExpression()).withMisfireHandlingInstructionDoNothing();
            //按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                    .withSchedule(scheduleBuilder).build();
            //修改参数
            if (!trigger.getJobDataMap().get("invokeParam").equals(appQuartz.getInvokeParam())) {
                trigger.getJobDataMap().put("invokeParam", appQuartz.getInvokeParam());
            }
            //按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
            return "success";
        } else {
            return "job or trigger not exists";
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值