quartz 集成 到spring boot 中
有个偷懒的方法 直接引用 这个 但是这个不是spring组织搞 的
1:gradle 依赖配置
1 | buildscript { |
2:指明 quartz 配置文件
这个是那个starter-quartz中的配置
1 | quartz: |
3:配置 quartz
就是从 quartz 中copy出来的 改成jdbc 存储
1 | org.quartz.scheduler.instanceName:DefaultQuartzScheduler |
4:重头戏 代理job 使用spring bean 中定义的job
先声明 这个是抄袭的 加上我自己的一点点想法
原方案 只能支持spring bean 的 我扩展了一波 可使用groovy 来扩充配置、扩充bean
前几个步骤都是集成进来 这一步 是将 quartz 的job 代理执行 使用注册在spring 中的job bean 执行 任务
- 方便管理
- 可以使用 groovy 动态注入配置,job
- 方便嵌入其他业务 如日志 等等
4.1:继承spring中QuartzJobBean 实现基础的job抽象类
通过建立抽象方法doExecute 将任务执行内容代理到实现这个抽象方法的job中4.2:建立代理执行类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.io.Serializable;
/**
* 基础job 抽象类
*
* @author ming
* @date 2017-11-09 16:32
*/
//表示 Quartz 将会在成功执行 execute() 方法后(没有抛出异常)更新 JobDetail 的 JobDataMap,下一次执行相同的任务(JobDetail)将会得到更新后的值,而不是原始的值。
@PersistJobDataAfterExecution
//禁止 并发执行 job
@DisallowConcurrentExecution
public abstract class BaseJob extends QuartzJobBean implements Serializable {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
doExecute(context);
}
/**
* 使用代理执行
*
* @param context
* @throws JobExecutionException
* @author ming
* @date 2017-11-09 16:08
*/
protected abstract void doExecute(JobExecutionContext context) throws JobExecutionException;
}
实现doExecute 方法
第一 指定 job实例来源于spring 容器
第二 可以插入其他业务 例如日志 之类的4.3:建立基础代理job抽象类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40/**
* 代理执行 job 前后处理日志
*
* @author ming
* @date 2017-11-09 16:11
*/
@Slf4j
public class ProxyJob extends BaseJob {
@Override
protected void doExecute(JobExecutionContext context) throws JobExecutionException {
/* if (schedulerManageDao == null) {
schedulerManageDao = applicationContext.getBean(SchedulerManageDao.class);
}*/
// 执行
JobDetail jobDetail = context.getJobDetail();
String jobName = jobDetail.getKey().getName();
BaseProxyJob job;
Date beginTime = new Date();
// Long dispatchId = schedulerManageDao.addDispatchLog(ApplicationConfig.SCHEDULER_CLUSTER_NAME, ApplicationConfig.SCHEDULER_INSTANCE_NAME, beginTime.getTime(), 0L, jobName, ScheduleExecuteLog.STATUS_BEGIN, 0L, "");
try {
job = SpringBeanManager.getbeanByNameAndType(jobName, BaseProxyJob.class);
job.execute();
log.info("[执行成功]" + jobName);
Date endTime = new Date();
// 记录任务完成
//schedulerManageDao.updateDispatchLogById(dispatchId, ScheduleExecuteLog.STATUS_SUCCESS, endTime.getTime(), endTime.getTime() - beginTime.getTime(), null);
} catch (Exception e) {
log.error("[执行异常]" + jobName + ":::" + e.getMessage());
Date endTime = new Date();
// 打印异常并发送异常
// String exceptionMessage = ExceptionUtils.getStackTrace(e);
//logger.error("[doProcess][job({}) 异常:{}]", jobName, exceptionMessage);
//if (dispatchId != null) {
// schedulerManageDao.updateDispatchLogById(dispatchId, ScheduleExecuteLog.STATUS_FAILURE, endTime.getTime(), endTime.getTime() - beginTime.getTime(), exceptionMessage);
//}
}
}
}4.4:细分job类型1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import lombok.extern.slf4j.Slf4j;
/**
* 定时器具体任务实现任务基类。所有子类需要继承它.
* <pre>
* 2. 使用{@link #setMemo(String)}可以设置任务结束后备注
* 3. 当任务出现异常时,会被记录到日志里并标记任务失败。所以任务的异常需要抛出来,不要catch掉不抛出。
* 4. 记得实现类加{@link org.springframework.stereotype.Service}注解,让它可以被spring扫描到
* </pre>
*
* @author ming
* @date 2017-11-09 16:32
*/
@Slf4j
public abstract class BaseProxyJob {
/**
* 任务执行完之后的备注
*/
private String memo;
/**
* 实现
*/
public abstract void execute();
public String getMemo() {
return memo;
}
/**
* 设置执行后备注
*
* @param memo 备注
*/
public void setMemo(String memo) {
this.memo = memo;
}
}
这个是在上面的基础上继续细化job的来源类型
方便针对不同的job来进行处理 例如 groovy 脚本写的抽象类 需要从数据库中读取相关数据 动态注入到spring 容器中
所有的来自groovy 脚本的job抽象类所有直接java写的编译好的job抽象类1
2
3
4
5
6
7
8/**
* groovy job 实现这个接口
*
* @author ming
* @date 2017-11-08 16:59
*/
public abstract class BaseScriptJob extends BaseProxyJob {
}具体demo请参考:http://github.xujiuming.com 下mingqz项目1
2
3
4
5
6
7
8
9
/**
* java 实现的 实现这个接口
*
* @author ming
* @date 2017-11-08 16:59
*/
public abstract class BaseSimpleJob extends BaseProxyJob {
}
####总结:通过编写抽象类 将 具体要执行的业务 代理执行掉 这样 就可以利用spring 的特性 去用groovy 做动态job 避免每次变更 都要从新部署