springboot使用Quartz定时发送邮件

一、Quartz是什么
Quartz是开源调度框架

Quartz 具有以下特点

1.强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求;

2.灵活的应用方式,例如支持任务和调度的多种组合方式,支持调度数据的多种存储方式;

3.分布式和集群能力,Terracotta 收购后在原来功能基础上作了进一步提升。
quartz调度核心元素:

1.Scheduler:任务调度器,是实际执行任务调度的控制器。在spring中通过SchedulerFactoryBean封装起来。

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

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

4.JobDetail:用来描述Job实现类及其它相关的静态信息,如Job名字、关联监听器等信息。在spring中有JobDetailFactoryBean和 MethodInvokingJobDetailFactoryBean两种实现,如果任务调度只需要执行某个类的某个方法,就可以通过MethodInvokingJobDetailFactoryBean来调用。

5.Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中。实现Job接口的任务,默认是无状态的,若要将Job设置成有状态的,在quartz中是给实现的Job添加@DisallowConcurrentExecution注解(以前是实现StatefulJob接口,现在已被Deprecated),在与spring结合中可以在spring配置文件的job detail中配置concurrent参数。

Quartz是一个强大任务调度框架,有很多的应用场景,在这里只使用Quartz定时发送邮件

二、使用Quartz之前的准备
1.创建springboot项目

2.引入需要的依赖

 
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
        
            org.springframework.boot
            spring-boot-devtools
            true
        
        
        
            org.springframework.boot
            spring-boot-starter-mail
        
        
        
            org.quartz-scheduler
            quartz-jobs
            2.2.1
        

三.发送邮件的准备
见前面代码

四.编写Quartz任务
1.定义一个工作工厂,JobFactory

package com.javaemaildemo.conf;

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 ${lcl}
 * @Title: JobFactory
 * @ProjectName javaemaildemo
 * @Description: TODO
 * @date 2019/2/27 002716:06
 */
@Component
public class JobFactory extends AdaptableJobFactory {
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        //调用父类的方法
        Object jobInstance = super.createJobInstance(bundle);
        //进行注入
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}

2.创建QuartzConfigration类,开始从定时器工厂中,找到定时器Bean。

package com.javaemaildemo.conf;

import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

/**
 * @author ${lcl}
 * @Title: QuartzConfigration
 * @ProjectName javaemaildemo
 * @Description: TODO
 * @date 2019/2/27 002715:23
 */
@Configuration
@EnableScheduling
public class QuartzConfigration {

    @Autowired
    private JobFactory jobFactory;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        schedulerFactoryBean.setJobFactory(jobFactory);
        return schedulerFactoryBean;
    }


    // 创建schedule
    @Bean(name = "scheduler")
    public Scheduler scheduler() {
        return schedulerFactoryBean().getScheduler();
    }
}

3.创建IQuartzService接口,处理Quartz业务逻辑

package com.javaemaildemo.service;

/**
 * @author ${lcl}
 * @Title: IQuartzService
 * @ProjectName javaemaildemo
 * @Description: TODO
 * @date 2019/2/27 002716:23
 */
public interface IQuartzService{
     void startJob(String time, String jobName, String group, Class job);

    /****
     * 暂停一个任务
     * @param triggerName
     * @param triggerGroupName
     */
     void pauseJob(String triggerName, String triggerGroupName);
    /****
     * 暂停重启一个定时器任务
     * @param triggerName
     * @param triggerGroupName
     */
     void resumeJob(String triggerName, String triggerGroupName);

    /****
     * 删除一个定时器任务,删除了,重启就没什么用了
     * @param triggerName
     * @param triggerGroupName
     */
     void deleteJob(String triggerName, String triggerGroupName);

    /***
     * 根据出发规则匹配任务,立即执行定时任务,暂停的时候可以用
     */
     void doJob(String triggerName, String triggerGroupName);

    /***
     * 开启定时器,这时才可以开始所有的任务,默认是开启的
     */
     void startAllJob();

    /**
     * 关闭定时器,则所有任务不能执行和创建
     */
     void shutdown();

}

4.创建QuartzServiceImpl实现接口类

package com.javaemaildemo.service.impl;
import com.javaemaildemo.service.IQuartzService;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;
/**
 * @author ${lcl}
 * @Title: QuartzServiceImpl
 * @ProjectName javaemaildemo
 * @Description: TODO
 * @date 2019/2/27 002716:08
 */
/**
 SimpleScheduleBuilder是简单调用触发器,它只能指定触发的间隔时间和执行次数;
 CronScheduleBuilder是类似于Linux Cron的触发器,它通过一个称为CronExpression的规则来指定触发规则,通常是每次触发的具体时间;(关于CronExpression,详见:官方,中文网文)
 CalendarIntervalScheduleBuilder是对CronScheduleBuilder的补充,它能指定每隔一段时间触发一次。
 */

@Service
public class QuartzServiceImpl implements IQuartzService {

    @Autowired
    private Scheduler scheduler;
    @Override
    public void startJob(String time, String jobName, String group, Class job) {
        try {
            // 创建jobDetail实例,绑定Job实现类
            // 指明job的名称,所在组的名称,以及绑定job类
            JobDetail jobDetail = JobBuilder.newJob(job).withIdentity(jobName, group).build();//设置Job的名字和组
            //corn表达式  每x秒执行一次
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(time);
            //设置定时任务的时间触发规则
            CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName, group).withSchedule(scheduleBuilder).build();
            System.out.println(scheduler.getSchedulerName());
            // 把作业和触发器注册到任务调度中, 启动调度
            scheduler.scheduleJob(jobDetail, cronTrigger);
        /*
        // 启动调度
         scheduler.start();
         Thread.sleep(30000);
        // 停止调度
        scheduler.shutdown();*/
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    /****
     * 暂停一个任务
     * @param triggerName
     * @param triggerGroupName
     */
    @Override
    public void pauseJob(String triggerName, String triggerGroupName) {
        try {
            JobKey jobKey = new JobKey(triggerName, triggerGroupName);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (jobDetail == null) {
                return;
            }
            System.out.println("开始暂停一个定时器");
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /****
     * 暂停重启一个定时器任务
     * @param triggerName
     * @param triggerGroupName
     */
    @Override
    public void resumeJob(String triggerName, String triggerGroupName) {
        try {
            JobKey jobKey = new JobKey(triggerName, triggerGroupName);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (jobDetail == null) {
                return;
            }
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }


    /****
     * 删除一个定时器任务,删除了,重启就没什么用了
     * @param triggerName
     * @param triggerGroupName
     */
    @Override
    public void deleteJob(String triggerName, String triggerGroupName) {
        try {
            JobKey jobKey = new JobKey(triggerName, triggerGroupName);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (jobDetail == null) {
                return;
            }
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }


    /***
     * 根据出发规则匹配任务,立即执行定时任务,暂停的时候可以用
     */
    @Override
    public void doJob(String triggerName, String triggerGroupName) {
        try {
            JobKey jobKey = JobKey.jobKey(triggerName, triggerGroupName);
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }


    /***
     * 开启定时器,这时才可以开始所有的任务,默认是开启的
     */
    @Override
    public void startAllJob() {
        try {
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭定时器,则所有任务不能执行和创建
     */
    @Override
    public void shutdown() {
        try {
            scheduler.shutdown();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}


5.创建任务HelloJob继承job类

package com.javaemaildemo.job;

import com.javaemaildemo.service.IEmailService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ResponseBody;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author ${lcl}
 * @Title: HelloJob
 * @ProjectName javaemaildemo
 * @Description: TODO
 * @date 2019/2/27 002713:13
 */
public class HelloJob implements Job {
    @Autowired
    private IEmailService emailService;
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //打印当前的执行时间 例如 2017-11-23 00:00:00
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("现在的时间是:" + sf.format(date));
        //具体的业务逻辑
        System.out.println("开始任务");
         emailService.sendAttachmentMail("[email protected]","定时发送时","下午好");
    }
}

6.QuartzConfigration控制执行,注意观察控制台

package com.javaemaildemo.controller;

import com.javaemaildemo.job.HelloJob;
import com.javaemaildemo.service.IQuartzService;
import com.javaemaildemo.service.impl.QuartzServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author ${lcl}
 * @Title: QuartzController
 * @ProjectName javaemaildemo
 * @Description: TODO
 * @date 2019/2/27 002716:11
 */
@RestController
public class QuartzController {

    @Resource
    private IQuartzService quartzService;


    @GetMapping("quartzStart")
    public String startNNoQuartz() {
        quartzService.startJob("0 23 10 * * ? ", "job1", "gropu1", HelloJob.class);
//        quartzService.startJob("0/2 * * * * ? ", "job2", "gropu2", HelloJoTwo.class);

        return "定时器任务开始执行,请注意观察控制台";
    }

    @GetMapping("pauseJob")
    public String pauseJob() {
        quartzService.pauseJob("job1", "gropu1");
        return "暂停一个定时器任务,请注意观察控制台";
    }


    @GetMapping("resumeJob") //shutdown关闭了,或者删除了就不能重启了
    public String resumeJob() {
        quartzService.resumeJob("job1", "gropu1");
        return "暂停重启一个定时器任务,请注意观察控制台";
    }

    @GetMapping("deleteJob")
    public String deleteJob() {
        quartzService.deleteJob("job1", "gropu1");
        return "删除一个定时器任务,请注意观察控制台,删除了,重启就没什么用了";
    }


    @GetMapping("doJob")
    public String doJob() {
        quartzService.doJob("job1", "gropu1");
        return "根据出发规则匹配任务,立即执行定时任务,暂停的时候可以用";
    }

    @GetMapping("startAllJob")
    public String startAllJob() {
        quartzService.startAllJob();
        return "开启定时器,这时才可以开始所有的任务,默认是开启的";
    }

    @GetMapping("shutdown")
    public String shutdown() {
        quartzService.shutdown();
        return "关闭定时器,则所有任务不能执行和创建";
    }
}

运行项目,效果如下:springboot使用Quartz定时发送邮件_第1张图片
五.cron常见表达式

表达式 允许值
“0 0 12 * * ?” 每天中午12点触发
“0 15 10 ? * *” 每天上午10:15触发
“0 15 10 * * ? 2005” 2005年的每天上午10:15触发
“0 * 14 * * ?” 在每天下午2点到下午2:59期间的每1分钟触发
“0 0/5 14 * * ?” 在每天下午2点到下午2:55期间的每5分钟触发
“0 0/5 14,18 * * ?” 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
“0 0-5 14 * * ?” 在每天下午2点到下午2:05期间的每1分钟触发
“0 10,44 14 ? 3 WED” 每年三月的星期三的下午2:10和2:44触发
“0 15 10 ? * MON-FRI” 周一至周五的上午10:15触发
“0 15 10 15 * ?” 每月15日上午10:15触发
“0 15 10 L * ?” 每月最后一日的上午10:15触发
“0 15 10 ? * 6L” 每月的最后一个星期五上午10:15触发
“0 15 10 ? * 6L 2002-2005” 2002年至2005年的每月的最后一个星期五上午10:15触发
“0 15 10 ? * 6#3” 每月的第三个星期五上午10:15触发
0 6 * * * 每天早上6点
0 /2 * * 每两个小时
0 23-7/2,8 * * * 晚上11点到早上8点之间每两个小时,早上八点
0 11 4 * 1-3 每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点
0 4 1 1 * 1月1日早上4点

你可能感兴趣的:(学习笔记,教程)