一、开发概述 😐
1.它是由OpenSymphony提供的、开源的、java编写的强大任务调度框架
2.几乎可以集成到任何规模的运用程序中,如简单的控制台程序,复杂的大规模分布式电子商务系统
3.可用于创建简单的或复杂的计划任务
4.包含很多企业级功能,如支持JTA和集群等
本篇文章,主要从Quartz框架核心组件,Quartz基本运行原理,Quartz核心概念和Quartz基本功能实现(代码)等方面来介绍Quartz。
二 、Quartz原理 😐
(一)Quartz关键组件 😐
Quartz比较关键的两个核心组件分别为Job和Trigger
job–表示任务是什么
trigger–表示何时触发任务
(二)Quartz几个关键概念 😐
1.IJob
public interface IJob
{
void Execute(JobExecutionContext context);
}
在Quartz中,所有的job任务,必须实现该接口
public class MyJob : IJob
{
public void Execute(JobExecutionContext context)
{
Console.WriteLine("Quartz基本功能测试。");
}
}
2.JobDetail
JobDetail,顾名思义,就是表示关于每个Job的相关信息,它主要包括两个核心组件,即Job Task和JobData Map
3.Trigger
Trigger,表示触发器,根据配置规则来触发执行计划调度job,它主要包括两个核心组件,即SimpleTrigger和CronTrigger
4.IJobStore
IJobStore,表述任务存储器,主要存储job和trigger相关信息。
5.ISchedulerFactory
ISchedulerFactory,表示任务计划工厂,用来管理任务计划IScheduler。
6.IScheduler
IScheduler,表述任务计划,它相当于一个容器,具体job和job相关trigger就能够被注入其中,从而实现任务计划调度。其主要常用的方法:
Start --启动执行计划
Shutdowm --关闭执行计划
接口Code:
(三)核心UML图 😐
三、代码实现
本示例,我们将使用.net 控制台程序,基于VS2017来使用Quartz建立一个任务:
任务要求:要求在控制台每隔2秒输出:Quartz基本功能测试。
1.首先使用Nuget下载Quartz
本示例使用的Quartz版本为1.0.3
2.按照如下步骤操作
代码: 😐
① .创建QUartzConfig配置类
/**
* @Author: ycw
* @Description: TODO
* @DateTime: 2021/9/13 13:14
**/
@Configuration
@EnableScheduling
public class QuartzConfig {
@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();
}
}
② .QuartzController
/**
* @Author: ycw
* @Description: TODO
* @DateTime: 2021/9/13 14:01
**/
@RestController
@Slf4j
@CrossOrigin(allowCredentials = "true")
@RequestMapping("/quartz")
public class QuartzController {
@Autowired
private IQuartzService iQuartzService;
@ApiOperation(value = "定时发邮件")
@RecordLog(value = "定时发送邮件",operateType = 2)
@GetMapping("/senMail")
public R startQuartz(String cron) {
iQuartzService.startJob(cron, "zz", "zz");
//参数 第一个是cron表达式 每五秒一次 第二个是job名称 第三个是所在组名称
// iQuartzService.startJob("*/5 * * * * ? ", "zz", "zz");
return R.ok();
}
}
③ .自定义IQuartzService
/**
* @Author: ycw
* @Description: TODO
* @DateTime: 2021/9/13 13:18
**/
public interface IQuartzService {
Boolean startJob(String time, String jobName, String group);
/****
* 暂停一个任务
* @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();
}
④ .实现类IQuartServiceImpl
package cn.cnic.service.impl;
import cn.cnic.job.SendEmailJob;
import cn.cnic.service.IQuartzService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Author: ycw
* @Description: TODO
* @DateTime: 2021/9/13 13:20
**/
@Service
@Slf4j
public class IQuartServiceImpl implements IQuartzService{
@Autowired
private Scheduler scheduler;
@Override
public Boolean startJob(String time, String jobName, String group) {
Boolean jobResult = false;
try {
// 创建jobDetail实例,绑定Job实现类
// 指明job的名称,所在组的名称,以及绑定job类
JobDetail jobDetail = JobBuilder.newJob(SendEmailJob.class).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);
jobResult = true;
} catch (Exception e) {
e.printStackTrace();
}
return jobResult;
}
/****
* 暂停一个任务
* @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();
}
}
}
⑥ .建立一个job包,存放自定义任务。
继承jJobFactory
/**
* @Author: ycw
* @Description: TODO
* @DateTime: 2021/9/13 13:15
**/
@Component
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
//生成一个job实例
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
实现Job接口自定义任务实现类
/**
* @Author: ycw
* @Description: TODO
* @DateTime: 2021/9/13 13:16
**/
@Slf4j
public class SendEmailJob implements Job {
// 设置固定的日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 将 yml 中的自定义配置注入到这里
@Value("${file.save-file-path}")
private String saveFilePath;
// 将 yml 中的发件人注入到这里
@Value("${spring.mail.username}")
private String fromEmail;
//注入spring发送邮件的对象
@Autowired
private ISendEmailService iSendEmailService;
@Autowired
private CImageMapper cImageMapper;
@Autowired
private CCustomerMapper cCustomerMapper;
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException{
//取当前年月
String date = sdf.format(new Date());
String year = DateUtil.getTimeStr(date,1);
String month = DateUtil.getTimeStr(date,2);
//查询当前年月的数据
QueryWrapper<CImage> cImageQueryWrapper = new QueryWrapper<>();
cImageQueryWrapper.eq("year",year).eq("month",month);
List<CImage> cImageList = null;
try {
cImageList = cImageMapper.selectList(cImageQueryWrapper);
} catch (Exception e) {
e.printStackTrace();
log.error("当月无数据!");
}
if(!CollectionUtils.isEmpty(cImageList)) {
Map<String, Object> map = new HashMap<>();
for (CImage cImage : cImageList) {
//根据id取出邮件
QueryWrapper<CCustomer> cCustomerQueryWrapper = new QueryWrapper<>();
cCustomerQueryWrapper.eq("id", cImage.getCustomerId());
CCustomer cCustomer = cCustomerMapper.selectOne(cCustomerQueryWrapper);
String email = cCustomer.getEmail();
map.put(email, cImage.getFileName());
System.out.println("map:"+map);
}
Boolean isSend = iSendEmailService.sendAttachmentMail(map);
System.out.println(isSend);
if (!isSend){
throw new ExException(2001,"发送失败!");
}
}throw new ExException(2001,"邮件发送失败!");
}
}