Spring boot 下使用Quartz


项目中需要定时执行某个任务,功能包括
启动,重新启动,暂停,恢复,更新,添加,删除,查询
这些功能是通用的哈,可以拿来用在任何项目中
1. pom.xml

<!-- quartz -->

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

2. 实体类
这里用到了lombok,方便管理实体类(下几篇文章中会讲解lombok,swagger2,通用Mapperde等使用方式。都是一些方便开发的小技术)

@EqualsAndHashCode(callSuper = false)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "table_schedule_job")
public class ScheduleJobVo {
    @Id
    @Column(name = "Id")
    private String id = UUID.randomUUID().toString();

    /** 任务名称 */
    private String jobName;

    /** 任务类 */
    private String jobClass;

    /** 任务方法 */
    private String jobMethod;

    /** 任务状态 0禁用 1启用 2删除 */
    private String status;

    /** 任务运行时间表达式 */
    private String cronExpression;

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

    /** 计划开始时间 */
    private Timestamp planStartDate;

    /** 计划结束时间 */
    private Timestamp planEndDate;

    @Transient
    private Integer page = 1;

    @Transient
    private Integer rows = 10;

    public ScheduleJobVo(String id, String status) {
        super();
        this.id = id;
        this.status = status;
    }

}

3. 工具类 SpringUtil.java
用于获得Spring管理的Bean

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

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

        System.out.println("---------------------------------------------------------------------");

        System.out.println("========ApplicationContext配置成功,在普通类可以通过调用SpringUtils.getAppContext()获取applicationContext对象,applicationContext="+SpringUtil.applicationContext+"========");

        System.out.println("---------------------------------------------------------------------");
    }

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通过name获取 Bean.
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }

}

4. Service接口类 SchedulerService.java

public interface SchedulerService {

    /**
     * @Description: 创建任务调度
     * @param parms
     * @param name
     * @param group
     * @param cronExpression
     * @param c
     * @throws Exception
     */
    public void createScheduler(ScheduleJobVo job) throws SchedulerException;

    /**
     * @Description: 删除任务
     * @param name
     *            工作名称
     * @param group
     *            工作组
     * @throws SchedulerException
     * @throws ParseException
     */
    public boolean deleteJob(String name) throws SchedulerException;

    /**
     * @Description: 创建任务调度
     * @param parms
     *            工作参数
     * @param name
     *            工作名称
     * @param c
     *            类名称
     * @param minutes
     *            间隔执行时长(分钟),传参时,需把时间转换成分钟
     * @throws Exception
     */
    public void createSchedulerJob(Map<String, Object> parms, String name,
            Class<? extends Job> c, String cronExpression) throws Exception;

    /**
     * @Description: 暂停任务
     * @param name
     *            任务名称
     * @throws SchedulerException
     */
    public void pauseJob(String name) throws SchedulerException;

    /**
     * @Description:恢复任务
     * @param name
     *            任务名称
     * @throws SchedulerException
     */
    public void resumeJob(String name) throws SchedulerException;

    public void restartJob(ScheduleJobVo job) throws SchedulerException ;

}

5. Service实现类
一些调度器操作

@Service
@Slf4j
public class SchedulerServiceImpl implements SchedulerService {

    private static Scheduler scheduler;
    static {
        SchedulerFactory sf = new StdSchedulerFactory();
        try {
            scheduler = sf.getScheduler();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * @Description: 创建任务调度
     */
    public void createScheduler(ScheduleJobDto job) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName());
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        if (trigger == null) {
            JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactory.class)
                    .withIdentity(job.getJobName()).build();
            jobDetail.getJobDataMap().put("scheduleJob", job);
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                    .cronSchedule(job.getCronExpression());
            scheduleBuilder.withMisfireHandlingInstructionDoNothing();
            // 按新的cronExpression表达式构建一个新的trigger
            try {
                TriggerBuilder<CronTrigger> triggerBuilder = TriggerBuilder
                        .newTrigger().withIdentity(triggerKey)
                        .withSchedule(scheduleBuilder);
                if (job.getPlanStartDate() != null) {
                    triggerBuilder.startAt(DateUtil.timestampToDate(job.getPlanStartDate()));
                } else {
                    triggerBuilder.startNow();
                }
                if (job.getPlanEndDate() != null) {
                    triggerBuilder.endAt(DateUtil.timestampToDate(job.getPlanEndDate()));
                }

                trigger = triggerBuilder.build();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
            try {
                scheduler.scheduleJob(jobDetail, trigger);
                if (!scheduler.isShutdown()) {
                    scheduler.start();
                }
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @Description: 删除任务
     * @param name
     *            JOB名称
     */
    public boolean deleteJob(String name) throws SchedulerException {
        TriggerKey triggerKey = new TriggerKey(name);
        Trigger trigger = scheduler.getTrigger(triggerKey);
        if (trigger != null) {
            JobKey jobKey = JobKey.jobKey(name);
            scheduler.pauseTrigger(triggerKey);// 停止触发器
            scheduler.unscheduleJob(triggerKey);// 移除触发器
            return scheduler.deleteJob(jobKey);// 移除当前进程的Job
        }
        return false;
    }

    /**
     * @Description: 创建任务调度
     * @param parms
     *            工作参数
     * @param name
     *            工作名称
     * @param c
     *            类名称
     * @param minutes
     *            间隔执行时长(分钟),传参时,需把时间转换成分钟
     * @throws Exception
     */
    public void createSchedulerJob(Map<String, Object> parms, String name,
            Class<? extends Job> c, String cronExpression) throws Exception {
        JobDetail job = JobBuilder.newJob(c).withIdentity(name).build();
        if (parms != null && !parms.isEmpty()) {
            JobDataMap dataMap = job.getJobDataMap();
            dataMap.putAll(parms);
        }
        CronScheduleBuilder builder = CronScheduleBuilder
                .cronSchedule(cronExpression);
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(name)
                .withSchedule(builder).build();
        scheduler.scheduleJob(job, trigger);
        scheduler.start();
        scheduler.isStarted();
    }

    /**
     * @Description: 暂停任务
     * @param name
     *            任务名称
     * @throws SchedulerException
     */
    public void pauseJob(String name) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(name);
        scheduler.pauseJob(jobKey);
        //需要补偿的话就注释掉触发器(后两句)
        //如果注释掉,当暂停一段时间后,再启动就会把暂停期间的任务全部执行一次
        TriggerKey triggerKey = TriggerKey.triggerKey(name);
        scheduler.pauseTrigger(triggerKey);
    }

    /**
     * @Description:恢复任务
     * @param name
     *            任务名称
     * @throws SchedulerException
     */
    public void resumeJob(String name) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(name);
        scheduler.resumeJob(jobKey);
        //需要补偿的话就注释掉触发器(后两句)
        //如果注释掉,当暂停一段时间后,再启动就会把暂停期间的任务全部执行一次
        TriggerKey triggerKey = TriggerKey.triggerKey(name);
        scheduler.resumeTrigger(triggerKey);
    }

    @Override
    public void restartJob(ScheduleJobVo job) throws SchedulerException {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName());
            //获取trigger,即在spring配置文件中定义的 bean id="myTrigger"
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            //修改按照新的执行策略执行,不允许修改立即执行一次
            scheduleBuilder.withMisfireHandlingInstructionDoNothing();
            //按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                    .withSchedule(scheduleBuilder).build();
            //按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

6. Job工厂
用来得到某个JOB

public class QuartzJobFactory implements Job {

    @Override
    public void execute(JobExecutionContext context)
            throws JobExecutionException {
        try {
            ScheduleJobVo scheduleJob = (ScheduleJobVo) context
                    .getMergedJobDataMap().get("scheduleJob");
            Object task = SpringUtil.getBean(scheduleJob.getJobClass());
            Class<?> demo = task.getClass();//得到类
            Method method = demo.getMethod(scheduleJob.getJobMethod());//得到方法
            method.invoke(task);//执行方法
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

7. Controler 控制类
以上有调度的Service方法,业务的Service自己写吧,就不贴出来了(对于ScheduleJobVo增删改查而已)

@Slf4j
@RestController
@RequestMapping("/quartz")
@Api(value = "/", description = "调度相关接口")
public class QuartzController {

    @Autowired
    private SchedulerService schedulerService;
    @Autowired
    private IScheduleJobService scheduleJobService;//ScheduleJobVo的Service实现类(你们自己去实现)
    //存储Job的id用
    private List<String> ids = new ArrayList<String>();

    @ResponseBody
    @PostConstruct
    //  被@PostConstruct修饰的方法会在服务器加载Servle的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。  
    public void initJob() {
        List<ScheduleJobVo> list = scheduleJobService.findEnableScheduleJob();//得到所有任务
        for (ScheduleJobVo scheduleJob : list) {
            if ((scheduleJob.getStatus().trim()).equals("1")) {//1:表示任务处于启动状态
                try {
                    log.info("调度启动开始=============================");
                    schedulerService.createScheduler(scheduleJob);
                    log.info("调度启动结束=============================");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                ids.add(scheduleJob.getId());//删除的时候用
            }

        }
    }

    @RequestMapping(value = "/startJob", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(notes = "/startJob", httpMethod = "GET", value = "启动trigger")
    public Response startJob(@RequestParam String id) {
        ScheduleJobVo job = scheduleJobService.findScheduleJob(id);
        if(job == null){
            return Response.failure("任务不存在");
        }
        try {
            schedulerService.createScheduler(job);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return new Response(Response.STATUS_OK,"启动成功");
        //Response是我自己实现的类,你们改成自己的返回值就好了。
    }

    @RequestMapping(value = "/restartJob", method = RequestMethod.GET)
    @ResponseBody
    //@ApiOperation 是swagger中的注解,不需要的可以删掉(后续会有专门讲解)
    @ApiOperation(notes = "/restartJob", httpMethod = "GET", value = "重新启动trigger")
    public Response restartJob(@RequestParam String id) {
        ScheduleJobVo job = scheduleJobService.findScheduleJob(id);
        if(job == null){
            return Response.failure("任务不存在");
        }
        try {
            schedulerService.restartJob(job);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return new Response(Response.STATUS_OK,"重新启动成功");
    }

    @RequestMapping(value = "/pauseJob/{id}", method = RequestMethod.PATCH)
    @ResponseBody
    @ApiOperation(notes = "/pauseJob/{id}", httpMethod = "PATCH", value = "暂停JOB")
    public Response pauseJob(@PathVariable String id) {
        ScheduleJobVo job = scheduleJobService.findScheduleJob(id);
        if(job == null){
            return Response.failure("任务不存在");
        }
        try {
            schedulerService.pauseJob(job.getJobName());
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        //更新数据库中任务状态
        Response response = scheduleJobService
                .updateScheduleJob(new ScheduleJobVo(id, "0"));

        return response;
    }

    @RequestMapping(value = "/resumeJob/{id}", method = RequestMethod.PATCH)
    @ResponseBody
    @ApiOperation(notes = "/resumeJob/{id}", httpMethod = "PATCH", value = "恢复JOB")
    public Response resumeJob(@PathVariable String id) {
        ScheduleJobVo job = scheduleJobService.findScheduleJob(id);
        if(job == null){
            return Response.failure("任务不存在");
        }
        try {
            schedulerService.resumeJob(job.getJobName());
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        //更新数据库中任务状态
        Response response = scheduleJobService
                .updateScheduleJob(new ScheduleJobVo(id, "1"));

        return response;
    }

    @RequestMapping(value = "/updateJob", method = RequestMethod.PUT)
    @ResponseBody
    @ApiOperation(notes = "/updateJob", httpMethod = "PUT", value = "更新JOB")
    public Response updateJob(@RequestBody ScheduleJobVo job) {
        Response response = scheduleJobService.updateScheduleJob(job);
        return response;
    }

    @RequestMapping(value = "/insertJob", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(notes = "/insertJob", httpMethod = "POST", value = "添加JOB")
    public Response insertJob(@RequestBody ScheduleJobVo job) {
        Response response = scheduleJobService.insertScheduleJob(job);
        return response;
    }

    @RequestMapping(value = "/deleteJob/{id}", method = RequestMethod.DELETE)
    @ResponseBody
    @ApiOperation(notes = "/deleteJob/{id}", httpMethod = "DELETE", value = "删除JOB")
    public Response deleteJob(@PathVariable String id) {
        ScheduleJobVo job = scheduleJobService.findScheduleJob(id);
        if(job == null){
            return Response.failure("任务不存在");
        }
        if (!ids.contains(id)) {//如果任务在启动列表中
            try {
                schedulerService.deleteJob(job.getJobName());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //更新数据库任务状态
        Response response = scheduleJobService
                .updateScheduleJob(new ScheduleJobVo(id, "2"));

        return response;
    }

    @RequestMapping(value = "/findJobs", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(notes = "/findJobs", httpMethod = "POST", value = "查询JOB")
    public Response findJobs(@RequestBody ScheduleJobVo job) {
        List<ScheduleJobVo> list = scheduleJobService.findJobs(job);

        return Response.success(new PageInfo<ScheduleJobVo>(list));
    }
}

8. 自己的JOB
就是@Component注解的简单类,例如:

@Component
public class DispatchJob {
    public void dispatch() {
        system.out.println("=====拯救世界的程序员=====");   
    }

}

9. 数据表
这里写图片描述

好了,到这里调度器已经完成,自己在控制台跑着玩玩吧^^

更新日志:2017-07-11 增加计划开始时间,计划结束时间
更新日志:2017-07-25 增加多实例解决方案QUARTZ多实例解决方案

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值