敞开成长之旅!这是我参与「日新方案 12 月更文挑战」的第30天,点击检查活动详情

1、什么是Quartz

quartz是一个功用丰厚的开源的使命调用体系,它能够界说很多job并发履行,支撑业务和集群

2、能够做什么

界说使命,在任何时刻,或许某一时刻能够做想履行的使命

3、Quartz 三要素:

  • Scheduler:使命调度器,一切的使命都是从这儿开端。
  • Trigger:触发器,定期履行使命,一般有cron表达式
  • JobDetail 使命详细
  • Job : 界说使命详细履行的逻辑,终究履行的逻辑

job 完成 QuartzJobBean ,abstractQuartzJob,使命履行的地方

Scheduler

留意:scheduler是一个接口类,一切的详细完成类都是经过SchedulerFactory工厂类完成,因此是需要装备调度工厂的,由他来调度使命

自界说SchedulerFactory(简略运用Quartz不需要自界说这个(留意)

@Bean
    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource)
    {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);
        // quartz参数
        Properties prop = new Properties();
        prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");
        prop.put("org.quartz.scheduler.instanceId", "AUTO");
        // 线程池装备
        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        prop.put("org.quartz.threadPool.threadCount", "20");
        prop.put("org.quartz.threadPool.threadPriority", "5");
        // JobStore装备
        prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
        // 集群装备
        prop.put("org.quartz.jobStore.isClustered", "true");
        prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
        // sqlserver 启用
        // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
        prop.put("org.quartz.jobStore.misfireThreshold", "12000");
        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
        factory.setQuartzProperties(prop);
        factory.setSchedulerName("RuoyiScheduler");
        // 延时发动
        factory.setStartupDelay(1);
        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
        // 可选,QuartzScheduler
        // 发动时更新己存在的Job,这样就不必每次修改targetObject后删去qrtz_job_details表对应记录了
        factory.setOverwriteExistingJobs(true);
        // 设置主动发动,默以为true
        factory.setAutoStartup(true);
        return factory;
    }

Trigger和JobDetail

常用办法

  • withIdentity() 给触发器一些属性 比如姓名,组名。

  • storeDurably() 耐久化存储

  • withSchedule(ScheduleBuilder schedBuilder) 以某种触发器触发。

简略示例

JobDetail jobDetail = JobBuilder.newJob(QuartzJobBean.class)
                .withIdentity("name1", "group1")
                .storeDurably(true)
                .build();

ScheduleBuilder(运用cronScheduler)

CronScheduleBuilder cronScheduleBuilder =
CronScheduleBuilder.cronSchedule(("0 0/5 * * * ?"));
@Bean
    public Trigger storeUserLikeAndCountTrigger(){
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().forJob(storeUserLikeAndCountJobDetail())
                .withIdentity("trigger1", "group1")
                .withSchedule(CronScheduleBuilder.cronSchedule(("0 0/5 * * * ?")))
                .startNow()  //当即发动
                .build();
        return cronTrigger;
    }

4、cron表达式写法

CornTrigger表达式的写法 * * * * * * 分别代表秒、分、时、日、月、周几

比如: 0 0 12 ? * 3 每周二中午 12 点履行使命 0 0 0 0 * ? 每月 1 日 0 点履行使命

字段 答应值 答应的特别字符

秒 0-59 , – * / 分 0-59 , – * / 小时 0-23 , – * / 日期 1-31 , – * ? / L W C 月份 1-12 或许 JAN-DEC , – * / 星期 1-7 或许 SUN-SAT , – * ? / L C # 年(可选) 留空, 1970-2099 , – * / 表达式 含义 “0 0 12 * * ?” 每天中午12点触发 “0 15 10 ? * *” 每天上午10:15触发 “0 15 10 * * ?” 每天上午10:15触发 “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触发

特别字符 含义 * 表明一切值; ? 表明未说明的值,即不关心它为何值; – 表明一个指定的规模; , 表明附加一个或许值; / 符号前表明开端时刻,符号后表明每次递增的值;

L(“last”) (“last”) “L” 用在day-of-month字段意思是 “这个月最终一天”;用在 day-of-week字段, 它简略意思是 “7” or “SAT”。 假设在day-of-week字段里和数字联合运用,它的意思便是 “这个月的最终一个星期几” – 例如: “6L” means “这个月的最终一个星期五”. 当咱们用“L”时,不指明一个列表值或许规模是很重要的,否则的话,咱们会得到一些意想不到的结果。

W(“weekday”) 只能用在day-of-month字段。用来描叙最接近指定天的作业日(周一到周五)。例如:在day-of-month字段用“15W”指“最接近这个月第15天的作业日”,即假设这个月第15天是周六,那么触发器将会在这个月第14天即周五触发;假设这个月第15天是周日,那么触发器将会在这个月第16天即周一触发;假设这个月第15天是周二,那么就在触发器这天触发。

留意一点:这个用法只会在当前月核算值,不会跳过当前月。“W”字符仅能在day-of-month指明一天,不能是一个规模或列表。也能够用“LW”来指定这个月的最终一个作业日。

只能用在day-of-week字段。用来指定这个月的第几个周几。例:在day-of-week字段用”6#3”指这个月第3个周五(6指周五,3指第3个)。假设指定的日期不存在,触发器就不会触发。

C 指和calendar联系后核算过的值。例:在day-of-month 字段用“5C”指在这个月第5天或之后包括calendar的第一天;在day-of-week字段用“1C”指在这周日或之后包括calendar的第一天

测试实例

1、导入依靠

<!-- 守时使命 -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>xxxx</version>
            <exclusions>
                <exclusion>
                    <groupId>com.mchange</groupId>
                    <artifactId>c3p0</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

版别依据springboot版别定,详细官网

2、导入Quartz数据库表

-- ----------------------------
-- 1、存储每一个已装备的 jobDetail 的详细信息
-- ----------------------------
drop table if exists QRTZ_JOB_DETAILS;
create table QRTZ_JOB_DETAILS (
    sched_name           varchar(120)    not null,
    job_name             varchar(200)    not null,
    job_group            varchar(200)    not null,
    description          varchar(250)    null,
    job_class_name       varchar(250)    not null,
    is_durable           varchar(1)      not null,
    is_nonconcurrent     varchar(1)      not null,
    is_update_data       varchar(1)      not null,
    requests_recovery    varchar(1)      not null,
    job_data             blob            null,
    primary key (sched_name,job_name,job_group)
) engine=innodb;
-- ----------------------------
-- 2、 存储已装备的 Trigger 的信息
-- ----------------------------
drop table if exists QRTZ_TRIGGERS;
create table QRTZ_TRIGGERS (
    sched_name           varchar(120)    not null,
    trigger_name         varchar(200)    not null,
    trigger_group        varchar(200)    not null,
    job_name             varchar(200)    not null,
    job_group            varchar(200)    not null,
    description          varchar(250)    null,
    next_fire_time       bigint(13)      null,
    prev_fire_time       bigint(13)      null,
    priority             integer         null,
    trigger_state        varchar(16)     not null,
    trigger_type         varchar(8)      not null,
    start_time           bigint(13)      not null,
    end_time             bigint(13)      null,
    calendar_name        varchar(200)    null,
    misfire_instr        smallint(2)     null,
    job_data             blob            null,
    primary key (sched_name,trigger_name,trigger_group),
    foreign key (sched_name,job_name,job_group) references QRTZ_JOB_DETAILS(sched_name,job_name,job_group)
) engine=innodb;
-- ----------------------------
-- 3、 存储简略的 Trigger,包括重复次数,距离,以及已触发的次数
-- ----------------------------
drop table if exists QRTZ_SIMPLE_TRIGGERS;
create table QRTZ_SIMPLE_TRIGGERS (
    sched_name           varchar(120)    not null,
    trigger_name         varchar(200)    not null,
    trigger_group        varchar(200)    not null,
    repeat_count         bigint(7)       not null,
    repeat_interval      bigint(12)      not null,
    times_triggered      bigint(10)      not null,
    primary key (sched_name,trigger_name,trigger_group),
    foreign key (sched_name,trigger_name,trigger_group) references QRTZ_TRIGGERS(sched_name,trigger_name,trigger_group)
) engine=innodb;
-- ----------------------------
-- 4、 存储 Cron Trigger,包括 Cron 表达式和时区信息
-- ---------------------------- 
drop table if exists QRTZ_CRON_TRIGGERS;
create table QRTZ_CRON_TRIGGERS (
    sched_name           varchar(120)    not null,
    trigger_name         varchar(200)    not null,
    trigger_group        varchar(200)    not null,
    cron_expression      varchar(200)    not null,
    time_zone_id         varchar(80),
    primary key (sched_name,trigger_name,trigger_group),
    foreign key (sched_name,trigger_name,trigger_group) references QRTZ_TRIGGERS(sched_name,trigger_name,trigger_group)
) engine=innodb;
-- ----------------------------
-- 5、 Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创立他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时分)
-- ---------------------------- 
drop table if exists QRTZ_BLOB_TRIGGERS;
create table QRTZ_BLOB_TRIGGERS (
    sched_name           varchar(120)    not null,
    trigger_name         varchar(200)    not null,
    trigger_group        varchar(200)    not null,
    blob_data            blob            null,
    primary key (sched_name,trigger_name,trigger_group),
    foreign key (sched_name,trigger_name,trigger_group) references QRTZ_TRIGGERS(sched_name,trigger_name,trigger_group)
) engine=innodb;
-- ----------------------------
-- 6、 以 Blob 类型存储寄存日历信息, quartz可装备一个日历来指定一个时刻规模
-- ---------------------------- 
drop table if exists QRTZ_CALENDARS;
create table QRTZ_CALENDARS (
    sched_name           varchar(120)    not null,
    calendar_name        varchar(200)    not null,
    calendar             blob            not null,
    primary key (sched_name,calendar_name)
) engine=innodb;
-- ----------------------------
-- 7、 存储已暂停的 Trigger 组的信息
-- ---------------------------- 
drop table if exists QRTZ_PAUSED_TRIGGER_GRPS;
create table QRTZ_PAUSED_TRIGGER_GRPS (
    sched_name           varchar(120)    not null,
    trigger_group        varchar(200)    not null,
    primary key (sched_name,trigger_group)
) engine=innodb;
-- ----------------------------
-- 8、 存储与已触发的 Trigger 相关的状况信息,以及相联 Job 的履行信息
-- ---------------------------- 
drop table if exists QRTZ_FIRED_TRIGGERS;
create table QRTZ_FIRED_TRIGGERS (
    sched_name           varchar(120)    not null,
    entry_id             varchar(95)     not null,
    trigger_name         varchar(200)    not null,
    trigger_group        varchar(200)    not null,
    instance_name        varchar(200)    not null,
    fired_time           bigint(13)      not null,
    sched_time           bigint(13)      not null,
    priority             integer         not null,
    state                varchar(16)     not null,
    job_name             varchar(200)    null,
    job_group            varchar(200)    null,
    is_nonconcurrent     varchar(1)      null,
    requests_recovery    varchar(1)      null,
    primary key (sched_name,entry_id)
) engine=innodb;
-- ----------------------------
-- 9、 存储少数的有关 Scheduler 的状况信息,假设是用于集群中,能够看到其他的 Scheduler 实例
-- ---------------------------- 
drop table if exists QRTZ_SCHEDULER_STATE; 
create table QRTZ_SCHEDULER_STATE (
    sched_name           varchar(120)    not null,
    instance_name        varchar(200)    not null,
    last_checkin_time    bigint(13)      not null,
    checkin_interval     bigint(13)      not null,
    primary key (sched_name,instance_name)
) engine=innodb;
-- ----------------------------
-- 10、 存储程序的悲观锁的信息(假设运用了悲观锁)
-- ---------------------------- 
drop table if exists QRTZ_LOCKS;
create table QRTZ_LOCKS (
    sched_name           varchar(120)    not null,
    lock_name            varchar(40)     not null,
    primary key (sched_name,lock_name)
) engine=innodb;
drop table if exists QRTZ_SIMPROP_TRIGGERS;
create table QRTZ_SIMPROP_TRIGGERS (
    sched_name           varchar(120)    not null,
    trigger_name         varchar(200)    not null,
    trigger_group        varchar(200)    not null,
    str_prop_1           varchar(512)    null,
    str_prop_2           varchar(512)    null,
    str_prop_3           varchar(512)    null,
    int_prop_1           int             null,
    int_prop_2           int             null,
    long_prop_1          bigint          null,
    long_prop_2          bigint          null,
    dec_prop_1           numeric(13,4)   null,
    dec_prop_2           numeric(13,4)   null,
    bool_prop_1          varchar(1)      null,
    bool_prop_2          varchar(1)      null,
    primary key (sched_name,trigger_name,trigger_group),
    foreign key (sched_name,trigger_name,trigger_group) references QRTZ_TRIGGERS(sched_name,trigger_name,trigger_group)
) engine=innodb;
commit;

3、 自界说调度器工厂

@Configuration
public class ScheduleConfig
{
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource)
    {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);
        // quartz参数
        Properties prop = new Properties();
        prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");
        prop.put("org.quartz.scheduler.instanceId", "AUTO");
        // 线程池装备
        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        prop.put("org.quartz.threadPool.threadCount", "20");
        prop.put("org.quartz.threadPool.threadPriority", "5");
        // JobStore装备
        prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
        // 集群装备
        prop.put("org.quartz.jobStore.isClustered", "true");
        prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
        // sqlserver 启用
        // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
        prop.put("org.quartz.jobStore.misfireThreshold", "12000");
        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
        factory.setQuartzProperties(prop);
        factory.setSchedulerName("RuoyiScheduler");
        // 延时发动
        factory.setStartupDelay(1);
        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
        // 可选,QuartzScheduler
        // 发动时更新己存在的Job,这样就不必每次修改targetObject后删去qrtz_job_details表对应记录了
        factory.setOverwriteExistingJobs(true);
        // 设置主动发动,默以为true
        factory.setAutoStartup(true);
        return factory;
    }
}

4、界说SysJob,存储创立的使命 便于反射调用办法

public class SysJob  implements Serializable
{
    private static final long serialVersionUID = 1L;
    /** 使命ID */
    private Long jobId;
    /** 使命称号 */
    private String jobName;
    /** 使命组名 */
    private String jobGroup;
    /** 调用方针字符串 */
    private String invokeTarget;
    /** cron履行表达式 */
    private String cronExpression;
    /** cron方案战略 */
    private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;
    /** 是否并发履行(0答应 1禁止) */
    private String concurrent;
    /** 使命状况(0正常 1暂停) */
    private String status;
    public Long getJobId()
    {
        return jobId;
    }
    public void setJobId(Long jobId)
    {
        this.jobId = jobId;
    }
    @NotBlank(message = "使命称号不能为空")
    @Size(min = 0, max = 64, message = "使命称号不能超过64个字符")
    public String getJobName()
    {
        return jobName;
    }
    public void setJobName(String jobName)
    {
        this.jobName = jobName;
    }
    public String getJobGroup()
    {
        return jobGroup;
    }
    public void setJobGroup(String jobGroup)
    {
        this.jobGroup = jobGroup;
    }
    @NotBlank(message = "调用方针字符串不能为空")
    @Size(min = 0, max = 500, message = "调用方针字符串长度不能超过500个字符")
    public String getInvokeTarget()
    {
        return invokeTarget;
    }
    public void setInvokeTarget(String invokeTarget)
    {
        this.invokeTarget = invokeTarget;
    }
    @NotBlank(message = "Cron履行表达式不能为空")
    @Size(min = 0, max = 255, message = "Cron履行表达式不能超过255个字符")
    public String getCronExpression()
    {
        return cronExpression;
    }
    public void setCronExpression(String cronExpression)
    {
        this.cronExpression = cronExpression;
    }
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    public Date getNextValidTime()
    {
        if (StringUtils.isNotEmpty(cronExpression))
        {
            return CronUtils.getNextExecution(cronExpression);
        }
        return null;
    }
    public String getMisfirePolicy()
    {
        return misfirePolicy;
    }
    public void setMisfirePolicy(String misfirePolicy)
    {
        this.misfirePolicy = misfirePolicy;
    }
    public String getConcurrent()
    {
        return concurrent;
    }
    public void setConcurrent(String concurrent)
    {
        this.concurrent = concurrent;
    }
    public String getStatus()
    {
        return status;
    }
    public void setStatus(String status)
    {
        this.status = status;
    }
    @Override
    public String toString() {
        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
            .append("jobId", getJobId())
            .append("jobName", getJobName())
            .append("jobGroup", getJobGroup())
            .append("cronExpression", getCronExpression())
            .append("nextValidTime", getNextValidTime())
            .append("misfirePolicy", getMisfirePolicy())
            .append("concurrent", getConcurrent())
            .append("status", getStatus())
            .append("createBy", getCreateBy())
            .append("createTime", getCreateTime())
            .append("updateBy", getUpdateBy())
            .append("updateTime", getUpdateTime())
            .append("remark", getRemark())
            .toString();
    }
}

4、界说详细使命job

4.1、笼统使命,使命履行日志

/**
 * 笼统quartz调用
 *
 */
public abstract class AbstractQuartzJob implements Job
{
    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
    /**
     * 线程本地变量
     */
    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
	// 当使命被触发,那么走这儿
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException
    {
    	// 存储使命信息的方针
        SysJob sysJob = new SysJob(); 
        // 将调度使命的JobDataMap中的属性,放入sysJob
        BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
        try
        {
        	// 履行使命之前
            before(context, sysJob);
            if (sysJob != null)
            {
            	// 履行真正的使命(笼统办法,由子类完成)
                doExecute(context, sysJob);
            }
            // 使命履行完后,使命履行记录
            after(context, sysJob, null);
        }
        catch (Exception e)
        {
            log.error("使命履行反常  - :", e);
            after(context, sysJob, e);
        }
    }
    /**
     * 履行前
     *
     * @param context 作业履行上下文方针
     * @param sysJob 体系方案使命
     */
    protected void before(JobExecutionContext context, SysJob sysJob)
    {
        threadLocal.set(new Date());
    }
    /**
     * 履行后
     *
     * @param context 作业履行上下文方针
     * @param sysJob 体系方案使命
     */
    protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
    {
        Date startTime = threadLocal.get();
        threadLocal.remove();
        final SysJobLog sysJobLog = new SysJobLog();
        xxxxxx使命信息
        // 写入数据库当中
        SpringUtils.getBean(XXX.class).addJobLog(sysJobLog);
    }
    /**
     * 履行办法,由子类重载
     *
     * @param context 作业履行上下文方针
     * @param sysJob 体系方案使命
     * @throws Exception 履行过程中的反常
     */
    protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
}

4.2 界说子类

履行使命子类

public class QuartzJobExecution extends AbstractQuartzJob
{
    @Override
    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
    {
    	// 反射履行使命
        jobInvokeUtil.invokeMethod(sysJob);
    }
}
并发履行使命子类
public class ConcurrentQuartzJobExecution extends AbstractQuartzJob
{
    @Override
    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
    {
        // 反射履行使命
        jobInvokeUtil.invokeMethod(sysJob);
    }
}

4.3 反射东西类

/**
 * 使命履行东西
 */
public class JobInvokeUtil {
    /**
     * 履行方针办法
     *
     * @param sysJob 体系使命
     */
    public static void invokeMethod(SysJob sysJob) throws Exception {
        // 获取调度方针  rg:myTask.noParamsMethod   前面为bean 的姓名,后面为办法名
        String invokeTarget = sysJob.getInvokeTarget();
        // 获取调度方针 bean称号
        String beanName = getBeanName(invokeTarget);
        // 获取调度方针 办法名
        String methodName = getMethodName(invokeTarget);
        // 获取调度方针 参数
        List<Object[]> methodParams = getMethodParams(invokeTarget);
        // beanName 不包括"." 即为正确beanName
        if (!isValidClassName(beanName)) {
            // 从容器中获取bean实例
            Object bean = SpringUtils.getBean(beanName);
            invokeMethod(bean, methodName, methodParams);
        } else {
            // 经过反射创立bean实例  此刻beanName的写法: com.xiaoxu.domain.Task
            Object bean = Class.forName(beanName).newInstance();
            invokeMethod(bean, methodName, methodParams);
        }
    }
    /**
     * 调用使命办法
     *
     * @param bean         方针方针
     * @param methodName   办法称号
     * @param methodParams 办法参数
     */
    private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
        if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0) {
            // 有参 经过method反射 调用
            Method method = bean.getClass().getDeclaredMethod(methodName, getMethodParamsType(methodParams));
            method.invoke(bean, getMethodParamsValue(methodParams));
        } else {
            // 无参 经过method反射 调用
            Method method = bean.getClass().getDeclaredMethod(methodName);
            method.invoke(bean);
        }
    }
    /**
     * 校验是否为为class包名
     *
     * @param invokeTarget 称号
     * @return true是 false否
     */
    public static boolean isValidClassName(String invokeTarget) {
        return StringUtils.countMatches(invokeTarget, ".") > 1;
    }
    /**
     * 获取bean称号
     *
     * @param invokeTarget 方针字符串
     * @return bean称号
     */
    public static String getBeanName(String invokeTarget) {
        // 取 target 在"("前  的子字符串
        String beanName = StringUtils.substringBefore(invokeTarget, "(");
        return StringUtils.substringBeforeLast(beanName, ".");
    }
    /**
     * 获取bean办法
     *
     * @param invokeTarget 方针字符串
     * @return method办法
     */
    public static String getMethodName(String invokeTarget) {
        String methodName = StringUtils.substringBefore(invokeTarget, "(");
        return StringUtils.substringAfterLast(methodName, ".");
    }
    /**
     * 获取method办法参数相关列表
     *
     * @param invokeTarget 方针字符串
     * @return method办法相关参数列表
     */
    public static List<Object[]> getMethodParams(String invokeTarget) {
        String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
        if (StringUtils.isEmpty(methodStr)) {
            return null;
        }
        String[] methodParams = methodStr.split(",");
        List<Object[]> classs = new LinkedList<>();
        for (int i = 0; i < methodParams.length; i++) {
            String str = StringUtils.trimToEmpty(methodParams[i]);
            // String字符串类型,包括'
            if (StringUtils.contains(str, "'")) {
                classs.add(new Object[]{StringUtils.replace(str, "'", ""), String.class});
            }
            // boolean布尔类型,等于true或许false
            else if (StringUtils.equals(str, "true") || StringUtils.equalsIgnoreCase(str, "false")) {
                classs.add(new Object[]{Boolean.valueOf(str), Boolean.class});
            }
            // long长整形,包括L
            else if (StringUtils.containsIgnoreCase(str, "L")) {
                classs.add(new Object[]{Long.valueOf(StringUtils.replaceIgnoreCase(str, "L", "")), Long.class});
            }
            // double浮点类型,包括D
            else if (StringUtils.containsIgnoreCase(str, "D")) {
                classs.add(new Object[]{Double.valueOf(StringUtils.replaceIgnoreCase(str, "D", "")), Double.class});
            }
            // 其他类型归类为整形
            else {
                classs.add(new Object[]{Integer.valueOf(str), Integer.class});
            }
        }
        return classs;
    }
    /**
     * 获取参数类型
     *
     * @param methodParams 参数相关列表
     * @return 参数类型列表
     */
    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) {
        Class<?>[] classs = new Class<?>[methodParams.size()];
        int index = 0;
        for (Object[] os : methodParams) {
            classs[index] = (Class<?>) os[1];
            index++;
        }
        return classs;
    }
    /**
     * 获取参数值
     *
     * @param methodParams 参数相关列表
     * @return 参数值列表
     */
    public static Object[] getMethodParamsValue(List<Object[]> methodParams) {
        Object[] classs = new Object[methodParams.size()];
        int index = 0;
        for (Object[] os : methodParams) {
            classs[index] = (Object) os[0];
            index++;
        }
        return classs;
    }
}

5、创立使命放入Scheduler调度器中,并发动使命

SchedulerUtils 调度器东西类

/**
 * 守时使命东西类
 */
public class ScheduleUtils {
    /**
     * 得到quartz使命类
     *
     * @param sysJob 履行方案
     * @return 详细履行使命类
     */
    private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) {
        // 默认值0  答应并发履行
        boolean isConcurrent = "0".equals(sysJob.getConcurrent());
        return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
    }
    /**
     * 构建使命触发方针
     */
    public static TriggerKey getTriggerKey(Long jobId, String jobGroup) {
        return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
    }
    /**
     * 构建使命键方针
     */
    public static JobKey getJobKey(Long jobId, String jobGroup) {
        return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
    }
    /**
     * 创立守时使命
     */
    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException {
        // 获取job class字节码(quartz使命类)  到底是并发仍是不并发
        Class<? extends Job> jobClass = getQuartzJobClass(job);
        // 构建job信息
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        // 经过jobBuilder 创立jobDetail(寄存job相关信息), 指定job类型(怎样履行job),指定jobKey
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
        // 表达式调度构建器   设置守时使命失败的战略  1:当即履行,2 履行一次,3 放弃履行
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
        // 按新的cronExpression表达式构建一个新的trigger  指定triggerKey   withSchedule:触发器时刻设定
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
                .withSchedule(cronScheduleBuilder).build();
        // 放入参数,运行时的办法能够获取
        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
        // 判断是否存在
        if (scheduler.checkExists(getJobKey(jobId, jobGroup))) {
            // 避免创立时存在数据问题 先移除,然后在履行创立操作
            scheduler.deleteJob(getJobKey(jobId, jobGroup));
        }
        // 调度容器设置JobDetail 和 Trigger
        scheduler.scheduleJob(jobDetail, trigger);
        // 暂停使命 经过jobKey
        if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {
            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
        }
    }
    /**
     * 设置守时使命战略
     */
    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)
            throws TaskException {
        switch (job.getMisfirePolicy()) {
            case ScheduleConstants.MISFIRE_DEFAULT:
                return cb;
            case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
                return cb.withMisfireHandlingInstructionIgnoreMisfires();
            case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
                return cb.withMisfireHandlingInstructionFireAndProceed();
            case ScheduleConstants.MISFIRE_DO_NOTHING:
                return cb.withMisfireHandlingInstructionDoNothing();
            default:
                throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()
                        + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);
        }
    }
}

大致履行流程

Springboot集成Quartz(任务存储在数据库)