Skip to content

Commit

Permalink
feat(scaffold): support integration with quartz
Browse files Browse the repository at this point in the history
chore: 集成 Quartz

style: adjust coding style

chore: simplify quartz demo usage

chore(scaffold): sort out commit message
  • Loading branch information
xiangtch committed Aug 6, 2020
1 parent 1b677de commit 0039fa4
Show file tree
Hide file tree
Showing 13 changed files with 387 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ $ yo deepexi-spring-cloud --help
|注册中心|✅eureka|✅consul|✅nacos|
|配置中心|✅Apollo|☑️Disconfig|☑️Config|✅nacos|
|消息队列|✅RabbitMQ|☑️RocketMQ|
|任务调度|☑️ES Job|☑️XXL-Job|☑️SiaTask|☑️Quartz|
|任务调度|☑️ES Job|☑️XXL-Job|☑️SiaTask|✅Quartz|
|RDBMS|✅MySQL|☑️PG SQL|☑️SQL Server|
|NoSQL|✅Redis|✅MongoDB|
|连接池|✅Druid|☑️Hikari|
Expand Down
3 changes: 2 additions & 1 deletion generators/app/handler/configurer/configurers.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ const types = [
'apm',
'mongodb',
'prometheus',
'docker'
'docker',
'schedule'
];

configurers.receive = (event, args) => {
Expand Down
39 changes: 39 additions & 0 deletions generators/app/handler/configurer/quartz_configurer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const _ = require('lodash');

module.exports = {
key: 'quartz',
fn: {
configureProviderPomDependencies (optionalDependencies) {
optionalDependencies.push({
dependency: [
{ groupId: 'org.springframework.boot' },
{ artifactId: 'spring-boot-starter-quartz' }
]
})
},
configureApplicationYaml (yaml, env) {
switch (env) {
case 'default': {
_.merge(yaml, {
spring: {
quartz: {
'job-store-type': 'memory',
properties: {
'org.quartz.threadPool.threadCount': 5,
'org.quartz.threadPool.threadPriority': 5,
'org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread': true,
'org.quartz.jobStore.misfireThreshold': 5000
}
}
}
});
break;
}

default: {
break;
}
}
}
}
}
18 changes: 18 additions & 0 deletions generators/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,19 @@ const obj = {
}

},

schedule: {
prompting: {
type: 'list',
choices: [
'quartz',
'none'
],
message: '请选择你使用的任务调度类型'
},
option: { desc: '任务调度', type: String, default: 'none' }
},

prometheus: {
prompting: {
type: 'confirm',
Expand All @@ -279,6 +292,7 @@ const obj = {
},
option: { desc: 'mongodb', type: Boolean, default: false }
},

demo: {
prompting: {
type: 'confirm',
Expand Down Expand Up @@ -363,6 +377,10 @@ module.exports = require('yo-power-generator').getGenerator(obj, {
}
}

if (props.schedule !== 'none') {
props.conditions[props.schedule] = true;
}

props.conditions[props.log] = true;

props.openfeign = props.discovery === 'eureka';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package ${basePackage}.controller;

import ${basePackage}.domain.dto.JobDemoCronDTO;
import ${basePackage}.domain.dto.JobDemoInfoDTO;
import ${basePackage}.service.JobDemoService;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

/**
* @author deepexi
*/
@RestController
@RequestMapping("demo/jobs")
@Payload
public class JobDemoController {

@Autowired
private JobDemoService jobDemoService;

/**
* 保存定时任务
*/
@PostMapping
public void save(@RequestBody @Valid JobDemoCronDTO dto) throws Exception {
jobDemoService.save(dto);
}

/**
* 删除定时任务
*/
@DeleteMapping
public void remove(@RequestBody @Valid JobDemoInfoDTO dto) throws SchedulerException {
jobDemoService.remove(dto);
}

/**
* 暂停定时任务
*/
@PutMapping("/pause")
public void pause(@RequestBody @Valid JobDemoInfoDTO dto) throws SchedulerException {
jobDemoService.pause(dto);
}

/**
* 恢复定时任务
*/
@PutMapping("/resume")
public void resumeJob(@RequestBody @Valid JobDemoInfoDTO dto) throws SchedulerException {
jobDemoService.resume(dto);
}

/**
* 修改定时任务,定时时间
*/
@PutMapping("/cron")
public void cronJob(@RequestBody @Valid JobDemoCronDTO dto) throws Exception {
jobDemoService.cron(dto);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package ${basePackage}.domain.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.validation.constraints.NotBlank;

/**
* @author deepexi
*/
@Data
@Accessors(chain = true)
@ApiModel
public class JobDemoCronDTO {

@ApiModelProperty(value = "全类名", example = "com.deepexi.job.DemoJob")
@NotBlank(message = "类名不能为空")
private String jobClassName;

@ApiModelProperty(value = "任务组名", example = "com.deepexi.job")
@NotBlank(message = "任务组名不能为空")
private String jobGroupName;

@ApiModelProperty(value = "定时任务cron表达式", example = "*/5 * * * * ?")
@NotBlank(message = "cron表达式不能为空")
private String cronExpression;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ${basePackage}.domain.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.validation.constraints.NotBlank;

/**
* @author deepexi
*/
@Data
@Accessors(chain = true)
@ApiModel
public class JobDemoInfoDTO {


@ApiModelProperty(value = "全类名", example = "com.deepexi.job.DemoJob")
@NotBlank(message = "类名不能为空")
private String jobClassName;

@ApiModelProperty(value = "任务组名", example = "com.deepexi.job")
@NotBlank(message = "任务组名不能为空")
private String jobGroupName;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ${basePackage}.job;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;

/**
* @author deepexi
*/
@Slf4j
public class DemoJob implements Job {
@Override
public void execute(JobExecutionContext context) {
log.error("Demo Job 执行时间: {}", DateUtil.now());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package ${basePackage}.service;

import ${basePackage}.domain.dto.JobDemoCronDTO;
import ${basePackage}.domain.dto.JobDemoInfoDTO;
import org.quartz.SchedulerException;

/**
* @author deepexi
*/
public interface JobDemoService {

/**
* 保存定时任务
* @param dto 定时任务详细信息
* @throws Exception 保存定时任务异常
*/
void save(JobDemoCronDTO dto) throws Exception;

/**
* 删除定时任务
* @param dto 定时任务基础信息
* @throws SchedulerException 删除定时任务异常
*/
void remove(JobDemoInfoDTO dto) throws SchedulerException;

/**
* 中止定时任务
* @param dto 定时任务基础信息
* @throws SchedulerException 中止定时任务异常
*/
void pause(JobDemoInfoDTO dto) throws SchedulerException;

/**
* 恢复定时任务
* @param dto 定时任务基础信息
* @throws SchedulerException 恢复定时任务异常
*/
void resume(JobDemoInfoDTO dto) throws SchedulerException;

/**
* 修改定时时间
* @param dto 定时任务详细信息
* @throws Exception 修改定时时间异常
*/
void cron(JobDemoCronDTO dto) throws Exception;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package ${basePackage}.service.impl;

import ${basePackage}.domain.dto.JobDemoCronDTO;
import ${basePackage}.domain.dto.JobDemoInfoDTO;
import ${basePackage}.service.JobDemoService;
import ${basePackage}.job.DemoJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
* @author deepexi
*/
@Service
@Slf4j
public class JobDemoServiceImpl implements JobDemoService {

@Autowired
private Scheduler scheduler;

@Override
public void save(JobDemoCronDTO dto) throws Exception {
JobDetail jobDetail = JobBuilder
.newJob(DemoJob.class)
.withIdentity(dto.getJobClassName(), dto.getJobGroupName())
.build();
CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(dto.getCronExpression());
CronTrigger trigger = TriggerBuilder
.newTrigger()
.withIdentity(dto.getJobClassName(), dto.getJobGroupName())
.withSchedule(cron)
.build();
try {
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
log.error("【定时任务】创建失败!", e);
throw new Exception("【定时任务】创建失败!");
}
}

@Override
public void remove(JobDemoInfoDTO dto) throws SchedulerException {
scheduler.pauseTrigger(TriggerKey.triggerKey(dto.getJobClassName(), dto.getJobGroupName()));
scheduler.unscheduleJob(TriggerKey.triggerKey(dto.getJobClassName(), dto.getJobGroupName()));
scheduler.deleteJob(JobKey.jobKey(dto.getJobClassName(), dto.getJobGroupName()));
}

@Override
public void pause(JobDemoInfoDTO dto) throws SchedulerException {
scheduler.pauseJob(JobKey.jobKey(dto.getJobClassName(), dto.getJobGroupName()));
}

@Override
public void resume(JobDemoInfoDTO dto) throws SchedulerException {
scheduler.resumeJob(JobKey.jobKey(dto.getJobClassName(), dto.getJobGroupName()));
}

@Override
public void cron(JobDemoCronDTO dto) throws Exception {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(dto.getJobClassName(), dto.getJobGroupName());

CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(dto.getCronExpression());

CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

scheduler.rescheduleJob(triggerKey, trigger);
} catch (SchedulerException e) {
log.error("【定时任务】更新失败!", e);
throw new Exception("【定时任务】创建失败!");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Quartz 任务调度

> Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵 活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,EJB作业预构建,JavaMail及其它,支持cron-like表达式等等。
## 如何使用

**Quartz API 关键的几个接口:**
- Scheduler:跟任务调度相关的最主要的API接口。
- Job:你期望任务调度执行的组件定义(调度器执行的内容),都必须实现该接口。
- JobDetail:用来定义Job的实例。
- Trigger:定义一个指定的Job何时被执行的组件,也叫触发器。
- JobBuilder:用来定义或创建JobDetail的实例,JobDetail限定了只能是Job的实例。
- TriggerBuilder:用来定义或创建触发器的实例。

调度器的生命周期,起始于SchedulerFactory的创建,终止于调用shutdown方法。当调度器接口实例创建完成后,就可以添加,删除和查询Jobs和Triggers对象,也可以执行其它的跟调度器相关的操作,比如中止触发器的触发。并且,调度器在调用start方法之前,不会触发任何一个触发器去执行作业任务。

具体样例可参考脚手架生成的对应 demo。

## 相关配置

```yaml
spring:
quartz:
job-store-type: memory
properties:
org.quartz.threadPool.threadCount: 5
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 5000
```

## 其他

更多配置请参考[spring-boot-starter-quartz](https://docs.spring.io/spring-boot/docs/2.0.0.M3/reference/html/boot-features-quartz.html)

更多使用方式请参考[Quartz中文文档](https://xuzongbao.gitbooks.io/quartz/content/)以及[官方文档](http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/migration-guide.html)

0 comments on commit 0039fa4

Please sign in to comment.