Quartz+Spring Boot实现动态管理定时任务

在实践中遇到动态管理定时任务的需求,场景通常是动态添加、更新、删除任务,借助Quartz,可方便实现功能。
以下使用Quartz结合Spring Boot方式使用。

POM依赖

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.2.RELEASE</version>
	<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context-support</artifactId>
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>

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

</dependencies>
代码

QuartzManager类管理任务的增删改查。

/**
 * @author wzx
 * @time 2018/6/9
 */
@Component
@Scope("singleton")
public class QuartzManager implements ApplicationContextAware {

    private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();

    private static final String JOB_DEFAULT_GROUP_NAME = "JOB_DEFAULT_GROUP_NAME";

    private static final String TRIGGER_DEFAULT_GROUP_NAME = "TRIGGER_DEFAULT_GROUP_NAME";

    private Logger logger = LoggerFactory.getLogger(QuartzManager.class);

    private ApplicationContext applicationContext;

    private Scheduler scheduler;

	 @Autowired
    private AutowiringSpringBeanJobFactory autowiringSpringBeanJobFactory;

    public void start() {
        //启动所有任务
        try {
            this.scheduler = schedulerFactory.getScheduler();
            scheduler.setJobFactory(autowiringSpringBeanJobFactory);
            //启动所有任务,这里获取AbstractTask的所有子类
            Map<String, AbstractTask> tasks = applicationContext.getBeansOfType(AbstractTask.class);
            tasks.forEach((k, v) -> {
                String cronExpression = v.getCronExpression();
                if (cronExpression != null) {
                    addJob(k, v.getClass().getName(), cronExpression);
                }
            });
            logger.info("start jobs finished.");
        } catch (SchedulerException e) {
            logger.error(e.getMessage(), e);
            throw new RuntimeException("init Scheduler failed");
        }
    }

    public boolean addJob(String jobName, String jobClass, String cronExp) {
        boolean result = false;
        if (!CronExpression.isValidExpression(cronExp)) {
            logger.error("Illegal cron expression format({})", cronExp);
            return result;
        }
        try {
            JobDetail jobDetail = JobBuilder.newJob().withIdentity(new JobKey(jobName, JOB_DEFAULT_GROUP_NAME))
                    .ofType((Class<Job>) Class.forName(jobClass))
                    .build();
            Trigger trigger = TriggerBuilder.newTrigger()
                    .forJob(jobDetail)
                    .withSchedule(CronScheduleBuilder.cronSchedule(cronExp))
                    .withIdentity(new TriggerKey(jobName, TRIGGER_DEFAULT_GROUP_NAME))
                    .build();
            scheduler.scheduleJob(jobDetail, trigger);
            scheduler.start();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            logger.error("QuartzManager add job failed");
        }
        return result;
    }

    public boolean updateJob(String jobName, String cronExp) {
        boolean result = false;
        if (!CronExpression.isValidExpression(cronExp)) {
            logger.error("Illegal cron expression format({})", cronExp);
            return result;
        }
        JobKey jobKey = new JobKey(jobName, JOB_DEFAULT_GROUP_NAME);
        TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_DEFAULT_GROUP_NAME);
        try {
            if (scheduler.checkExists(jobKey) && scheduler.checkExists(triggerKey)) {
                JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                Trigger newTrigger = TriggerBuilder.newTrigger()
                        .forJob(jobDetail)
                        .withSchedule(CronScheduleBuilder.cronSchedule(cronExp))
                        .withIdentity(new TriggerKey(jobName, TRIGGER_DEFAULT_GROUP_NAME))
                        .build();
                scheduler.rescheduleJob(triggerKey, newTrigger);
                result = true;
            } else {
                logger.error("update job name:{},group name:{} or trigger name:{},group name:{} not exists..",
                        jobKey.getName(), jobKey.getGroup(), triggerKey.getName(), triggerKey.getGroup());
            }
        } catch (SchedulerException e) {
            logger.error(e.getMessage(), e);
            logger.error("update job name:{},group name:{} failed!", jobKey.getName(), jobKey.getGroup());
        }
        return result;
    }

    public boolean deleteJob(String jobName) {
        boolean result = false;
        JobKey jobKey = new JobKey(jobName, JOB_DEFAULT_GROUP_NAME);
        try {
            if (scheduler.checkExists(jobKey)) {
                result = scheduler.deleteJob(jobKey);
            } else {
                logger.error("delete job name:{},group name:{} not exists.", jobKey.getName(), jobKey.getGroup());
            }
        } catch (SchedulerException e) {
            logger.error(e.getMessage(), e);
            logger.error("delete job name:{},group name:{} failed!", jobKey.getName(), jobKey.getGroup());
        }
        return result;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

定义抽象任务类AbstractTask,实现Job接口,子类Job实例需实现executeInternal方法。

/**
 * @author wzx
 * @time 2018/6/9
 */
public abstract class AbstractTask implements Job {
    
    private Logger logger = LoggerFactory.getLogger(AbstractTask.class);

    protected abstract void executeInternal(JobExecutionContext context);

    protected String cronExpression;

    @Override
    public void execute(JobExecutionContext context) {
        try {
            executeInternal(context);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            logger.error("job execute failed!");
        }
    }

    public String getCronExpression() {
        return cronExpression;
    }
}

测试TestTask类,继承AbstractTask类,实现executeInternal方法。

/**
 * @author wzx
 * @time 2018/6/9
 */
@Component("testTask")
public class TestTask extends AbstractTask {

    private Logger logger = LoggerFactory.getLogger(TestTask.class);

    @PostConstruct
    public void init() {
        this.cronExpression = "0/2 * * * * ? ";
    }

    @Override
    protected void executeInternal(JobExecutionContext context) {
        logger.info("test task start execute.");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            logger.info("test task execute interrupted.");
        }
        logger.info("test task execute end.");
    }
}

测试用例,测试增加、更新、删除功能。

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootdemoApplicationTests {

    private Logger logger = LoggerFactory.getLogger(SpringbootdemoApplicationTests.class);

    @Autowired
    private QuartzManager quartzManager;

    @Autowired
    private TestTask testTask;
    
    @Test
    public void testCronTest() throws InterruptedException {
        quartzManager.start();
        TimeUnit.SECONDS.sleep(10);
        logger.info("start update job");
        //修改任务
        quartzManager.updateJob("testTask", "0/3 * * * * ? ");
        logger.info("end update job");
        TimeUnit.SECONDS.sleep(10);
        logger.info("start delete job");
        //删除任务
        quartzManager.deleteJob("testTask");
        logger.info("end delete job");
        TimeUnit.SECONDS.sleep(10);
        //添加任务
        logger.info("start add job");
        quartzManager.addJob("testTask", testTask.getClass().getName(), "0/3 * * * * ?");
        logger.info("end add job");
        TimeUnit.SECONDS.sleep(10);
        //修改任务
        logger.info("start update job");
        quartzManager.updateJob("testTask", "0/3 * * * * ?");
        logger.info("end update job");
        TimeUnit.SECONDS.sleep(10);
        //删除任务
        logger.info("start delete job");
        quartzManager.deleteJob("testTask");
        logger.info("end delete job");
        logger.info("end.");
    }

}

结果输出,符合预期。

2018-06-09 16:43:58.052  INFO 2884 --- [           main] org.quartz.impl.StdSchedulerFactory      : Using default implementation for ThreadExecutor
2018-06-09 16:43:58.054  INFO 2884 --- [           main] org.quartz.simpl.SimpleThreadPool        : Job execution threads will use class loader of thread: main
2018-06-09 16:43:58.066  INFO 2884 --- [           main] org.quartz.core.SchedulerSignalerImpl    : Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
2018-06-09 16:43:58.066  INFO 2884 --- [           main] org.quartz.core.QuartzScheduler          : Quartz Scheduler v.2.3.0 created.
2018-06-09 16:43:58.066  INFO 2884 --- [           main] org.quartz.simpl.RAMJobStore             : RAMJobStore initialized.
2018-06-09 16:43:58.067  INFO 2884 --- [           main] org.quartz.core.QuartzScheduler          : Scheduler meta-data: Quartz Scheduler (v2.3.0) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.

2018-06-09 16:43:58.067  INFO 2884 --- [           main] org.quartz.impl.StdSchedulerFactory      : Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
2018-06-09 16:43:58.067  INFO 2884 --- [           main] org.quartz.impl.StdSchedulerFactory      : Quartz scheduler version: 2.3.0
2018-06-09 16:43:58.077  INFO 2884 --- [           main] org.quartz.core.QuartzScheduler          : Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
2018-06-09 16:43:58.077  INFO 2884 --- [           main] c.e.s.service.task.QuartzManager         : start jobs finished.
2018-06-09 16:43:58.081  INFO 2884 --- [eduler_Worker-1] c.e.s.service.task.TestTask              : test task start execute.
2018-06-09 16:44:01.082  INFO 2884 --- [eduler_Worker-1] c.e.s.service.task.TestTask              : test task execute end.
...
2018-06-09 16:44:08.077  INFO 2884 --- [           main] c.e.s.SpringbootdemoApplicationTests     : start update job
2018-06-09 16:44:08.078  INFO 2884 --- [           main] c.e.s.SpringbootdemoApplicationTests     : end update job
2018-06-09 16:44:09.001  INFO 2884 --- [eduler_Worker-7] c.e.s.service.task.TestTask              : test task start execute.
2018-06-09 16:44:12.002  INFO 2884 --- [eduler_Worker-7] c.e.s.service.task.TestTask              : test task execute end.
...
2018-06-09 16:44:18.078  INFO 2884 --- [           main] c.e.s.SpringbootdemoApplicationTests     : start delete job
2018-06-09 16:44:18.078  INFO 2884 --- [           main] c.e.s.SpringbootdemoApplicationTests     : end delete job
2018-06-09 16:44:28.079  INFO 2884 --- [           main] c.e.s.SpringbootdemoApplicationTests     : start add job
2018-06-09 16:44:28.079  INFO 2884 --- [           main] org.quartz.core.QuartzScheduler          : Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
2018-06-09 16:44:28.079  INFO 2884 --- [           main] c.e.s.SpringbootdemoApplicationTests     : end add job
2018-06-09 16:44:30.001  INFO 2884 --- [eduler_Worker-1] c.e.s.service.task.TestTask              : test task start execute.
2018-06-09 16:44:33.001  INFO 2884 --- [eduler_Worker-1] c.e.s.service.task.TestTask              : test task execute end.
...
2018-06-09 16:44:38.080  INFO 2884 --- [           main] c.e.s.SpringbootdemoApplicationTests     : start update job
2018-06-09 16:44:38.080  INFO 2884 --- [           main] c.e.s.SpringbootdemoApplicationTests     : end update job
2018-06-09 16:44:39.001  INFO 2884 --- [eduler_Worker-4] c.e.s.service.task.TestTask              : test task start execute.
2018-06-09 16:44:42.003  INFO 2884 --- [eduler_Worker-4] c.e.s.service.task.TestTask              : test task execute end.
...
2018-06-09 16:44:48.080  INFO 2884 --- [           main] c.e.s.SpringbootdemoApplicationTests     : start delete job
2018-06-09 16:44:48.080  INFO 2884 --- [           main] c.e.s.SpringbootdemoApplicationTests     : end delete job
2018-06-09 16:44:48.080  INFO 2884 --- [           main] c.e.s.SpringbootdemoApplicationTests     : end.
2018-06-09 16:44:48.083  INFO 2884 --- [       Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1da2cb77: startup date [Sat Jun 09 16:43:57 CST 2018]; root of context hierarchy

Job默认由Quartz管理,如果需要使用Spring容器管理bean,也就是依赖注入,需要指定JobFactory,也就是指定将Job由Spring容器管理。

/**
 * @author wzx
 * @time 2018/6/9
 */
@Component
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
    private transient AutowireCapableBeanFactory beanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        final Object jobInstance = super.createJobInstance(bundle);
        beanFactory.autowireBean(jobInstance);
        return jobInstance;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.beanFactory = applicationContext.getAutowireCapableBeanFactory();
    }
}

  • 5
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
使用Spring BootQuartz实现定时任务管理,可以让你更方便地管理和监控你的定时任务。下面是一个使用Spring BootQuartzSpring MVC实现定时任务管理的示例: 首先,在你的Spring Boot应用程序中添加QuartzSpring MVC的依赖项: ```xml <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 然后,在你的Spring Boot应用程序中创建一个Quartz的调度器,并添加一个Spring MVC的Controller来管理定时任务: ```java @Configuration public class QuartzConfig { @Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setTriggers(myTaskTrigger().getObject()); return schedulerFactoryBean; } @Bean public JobDetailFactoryBean myTaskJob() { JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean(); jobDetailFactoryBean.setJobClass(MyTask.class); return jobDetailFactoryBean; } @Bean public CronTriggerFactoryBean myTaskTrigger() { CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean(); cronTriggerFactoryBean.setJobDetail(myTaskJob().getObject()); cronTriggerFactoryBean.setCronExpression("0/5 * * * * ?"); // 每5秒执行一次 return cronTriggerFactoryBean; } } @RestController public class TaskController { @Autowired private Scheduler scheduler; @PostMapping("/tasks") public void addTask(@RequestBody TaskInfo taskInfo) throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(taskInfo.getJobClass()) .withIdentity(taskInfo.getJobName(), taskInfo.getJobGroup()) .build(); CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(taskInfo.getTriggerName(), taskInfo.getTriggerGroup()) .withSchedule(CronScheduleBuilder.cronSchedule(taskInfo.getCronExpression())) .build(); scheduler.scheduleJob(jobDetail, trigger); } @DeleteMapping("/tasks/{jobName}/{jobGroup}") public void deleteTask(@PathVariable String jobName, @PathVariable String jobGroup) throws SchedulerException { JobKey jobKey = new JobKey(jobName, jobGroup); scheduler.deleteJob(jobKey); } } ``` 在上面的代码中,我们创建了一个Spring MVC的Controller来管理定时任务。我们使用了Scheduler类来添加和删除定时任务。在添加定时任务时,我们使用了TaskInfo类来封装定时任务的信息。在删除定时任务时,我们使用了jobName和jobGroup来识别定时任务。 最后,在你的定时任务类中实现Job接口,并在类上添加@DisallowConcurrentExecution注解,以确保每个任务执行时只有一个实例: ```java @Component @DisallowConcurrentExecution public class MyTask implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 定时任务执行的代码 } } ``` 以上就是使用Spring BootQuartzSpring MVC实现定时任务管理的示例。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值