springboot结合quartz实现可在前端设置时间的定时任务

做项目时遇到一个需求,需要在web后台管理页面设置开关灯时间,然后实现灯源的自动开关操作

首先想到的是springboot自带的@Schedule注解,但是有个问题,因为我要在前端设置时间,而注解的实现方法只能是写一个死的cron表达式在那儿,要更改的话只能改代码,显然不符合要求

于是用了quartz,实现的效果是每十秒从数据库获取一次cron表达式,如果和当前定时任务的cron不同的话,重新设置定时任务,这样的话,前端就只用调用数据库的修改接口,就可以实现设置新的定时任务

pom.xml,springboot需要的就不多说了,这里是quartz需要的

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

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

然后在service里写任务的具体逻辑,这里是关掉所有灯,注意要加上@EnableScheduling

@Service
@EnableScheduling
public class QuartzServiceImpl implements QuartzService {
    @Autowired
    private QuartzConfigDao quartzConfigDao;

    @Autowired
    private LampDao lampDao;

    @Override
    public void closeAll() {
        lampDao.TurnOffAll();
        System.out.println("close all");
    }

}

然后是quartz相关的定时任务注册代码

public class QuartzConfig {
    /*
    配置定时任务
     */
    @Bean(name = "jobDetailAfterWork")
    public MethodInvokingJobDetailFactoryBean detailFactoryBean(QuartzService task){ //这里的参数就是我们刚才写的QuartzService的一个实例
        MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
        /*
         * 是否并发执行
         * 例如每5s执行一次任务,但是当前任务还没有执行完,就已经过了5s了,
         * 如果此处为true,则下一个任务会执行,如果此处为false,则下一个任务会等待上一个任务执行完后,再开始执行
         */
        jobDetail.setConcurrent(false);
        //设置定时任务的名字
        jobDetail.setName("AfterWork");
        //设置任务的分组,这些属性都可以在数据库中,在多任务的时候使用
        jobDetail.setGroup("srd");

        //为需要执行的实体类对应的对象
        jobDetail.setTargetObject(task);

        /*
         * closeAll为需要执行的方法
         * 通过这几个配置,告诉JobDetailFactoryBean我们需要执行定时执行QuartzService类中的closeAll方法
         */
        jobDetail.setTargetMethod("closeAll");
        return jobDetail;
    }


    /*
     配置定时任务的触发器,也就是什么时候触发执行定时任务
     */
    @Bean(name = "jobTriggerAfterWork")
    public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetail jobDetailAfterWork){
        CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
        trigger.setJobDetail(jobDetailAfterWork);
        //初始化的cron表达式(每天14:25:20触发)
        trigger.setCronExpression("20 25 14 * * ?");
        //trigger的name
        trigger.setName("AfterWorkTrigger");
        return trigger;
    }

    /*
     定义quartz调度工厂
     */
    @Bean(name = "scheduler")
    public SchedulerFactoryBean schedulerFactoryBean(Trigger jobTriggerAfterWork){
        SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
        //用于quartz集群,QuartzScheduler启动时更新已存在的job
        factoryBean.setOverwriteExistingJobs(true);
        //延时启动,应用启动1秒后
        factoryBean.setStartupDelay(1);
        //注册触发器
        factoryBean.setTriggers(jobTriggerAfterWork);
        return factoryBean;
    }
}

这些做完之后,再运行项目,这时候已经有一个定时任务在工作中了,它会在每天的14:25:20执行QuartzService的closeAll方法

接下来是设置定时查询数据库的cron并与当前定时任务对比,进行刷新

@EnableScheduling
@Configuration
@Component
public class QuartzRefreshConfig {
    @Autowired
    private QuartzService quartzService;

    @Resource(name = "jobTriggerAfterWork")
    private CronTrigger cronTriggerAfterWork;

    @Resource(name = "scheduler")
    private Scheduler scheduler;

    /*
    每隔10s查库,并根据查询结果决定是否重新设置定时任务
    */

    @Scheduled(fixedRate = 10000)
    public void scheduleUpdateCronTrigger() throws SchedulerException {
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(cronTriggerAfterWork.getKey());
        //当前Trigger使用的
        String currentCron = trigger.getCronExpression();
        //从数据库查询出来的
        String searchCron = quartzService.getTaskById(1); //这里是数据库的查询操作,根据自己的情况自己写

        if (currentCron.equals(searchCron)) {
            // 如果当前使用的cron表达式和从数据库中查询出来的cron表达式一致,则不刷新任务
        } else {
            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(searchCron);
            //按新的cronExpression表达式重新构建trigger
            trigger = (CronTrigger) scheduler.getTrigger(cronTriggerAfterWork.getKey());
            trigger = trigger.getTriggerBuilder().withIdentity(cronTriggerAfterWork.getKey()).withSchedule(scheduleBuilder).build();
            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(cronTriggerAfterWork.getKey(), trigger);
            currentCron = searchCron;
        }
    }
}

这样我们就完成了可以动态更新的定时任务

对于多个任务,只需要在QuartzConfig中定义多个jobDetail和对应的Trigger,然后在调度工厂进行注册就可以啦,注意多个任务时任务名,即jobdetail的名字和trigger的名字不要重复

猜你喜欢

转载自www.cnblogs.com/suru723/p/11328672.html