欢迎访问www.allbetgaming.com!

首页科技正文

保定招聘:SpringBoot集成Quartz实现准时义务

admin2020-05-0660

1 需求

在我的前后端星散的实验室治理项目中,有一个功效是学生状态统计。我的设计是按天统计每种状态的比例。为了便于盘算,在天天0点,系统需要将学生的状态重置,并插入一条数据作为一天的最先状态。另外,考虑到学生的请假需求,请假的申请往往是提前做好,等系统时间走到现实请假时间的时刻,系统要将学生的状态修改为请假。

显然,这两个子需求都可以通过准时义务实现。在网上略做搜索以后,我选择了对照盛行的准时义务框架Quartz。

2 Quartz

Quartz是一个准时义务框架,其他先容网上也很详尽。这里要先容一下Quartz里的几个异常焦点的接口。

2.1 Scheduler接口

Scheduler翻译成调剂器,Quartz通过调剂器来注册、暂停、删除Trigger和JobDetail。Scheduler还拥有一个SchedulerContext,顾名思义就是上下文,通过SchedulerContext我们可以获取到触发器和义务的一些信息。

2.2 Trigger接口

Trigger可以翻译成触发器,通过cron表达式或是SimpleScheduleBuilder等类,指界说务执行的周期。系统时间走到触发器指定的时间的时刻,触发器就会触发义务的执行。

2.3 JobDetail接口

Job接口是真正需要执行的义务。JobDetail接口相当于将Job接口包装了一下,Trigger和Scheduler现实用到的都是JobDetail。

3 SpringBoot官方文档解读

SpringBoot官方写了spring-boot-starter-quartz。使用过SpringBoot的同砚都知道这是一个官方提供的启动器,有了这个启动器,集成的操作就会被大大简化。

现在我们来看一看SpingBoot2.2.6官方文档,其中第4.20小节Quartz Scheduler就谈到了Quartz,但很可惜一共只有两页不到的内容,先来看看这么精髓的文档里能学到些什么。

Spring Boot offers several conveniences for working with the Quartz scheduler, including the
spring-boot-starter-quartz “Starter”. If Quartz is available, a Scheduler is auto-configured (through the SchedulerFactoryBean abstraction).
Beans of the following types are automatically picked up and associated with the Scheduler:
• JobDetail: defines a particular Job. JobDetail instances can be built with the JobBuilder API.
• Calendar.
• Trigger: defines when a particular job is triggered.

翻译一下:

SpringBoot提供了一些便捷的方式来和Quartz协同事情,这些方式内里包罗`spring-boot-starter-quartz`这个启动器。若是Quartz可用,Scheduler会通过SchedulerFactoryBean这个工厂bean自动设置到SpringBoot里。
JobDetail、Calendar、Trigger这些类型的bean会被自动采集并关联到Scheduler上。
Jobs can define setters to inject data map properties. Regular beans can also be injected in a similar manner.

翻译一下:

Job可以界说setter(也就是set方式)来注入设置信息。也可以用同样的方式注入通俗的bean。

下面是文档里给的示例代码,我直接完全照着写,拿到的却是null。不知道是不是我的使用方式有误。厥后仔细一想,文档的意思应该是在建立Job工具之后,挪用set方式将依赖注入进去。但后面我们是通过框架反射天生的Job工具,这样做反而会搞得加倍庞大。最后照样决议接纳给Job类加@Component注解的方式。

文档的其他篇幅就先容了一些设置,然则先容得也不周全,看了辅助也并不是很大。详细的设置可以参考w3school的Quartz设置。

4 SpringBoot集成Quartz

4.1 建表

我选择将准时义务的信息保留在数据库中,优点是显而易见的,准时义务不会由于系统的溃逃而丢失。

建表的sql语句在Quartz的github中可以找到,内里有针对每一种常用数据库的sql语句,详细地址是:Quartz数据库建表sql。

建表以后,可以看到数据库里多了11张表。我们完全不需要体贴每张表的详细作用,在添加删除义务、触发器等的时刻,Quartz框架会操作这些表。

4.2 引入依赖

pom.xml里添加依赖。

<!-- quartz 准时义务 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

4.3 设置quartz

application.yml中设置quartz。相关设置的作用已经写在注解上。

# spring的datasource等设置未贴出
spring:
  quartz:
      # 将义务等保留化到数据库
      job-store-type: jdbc
      # 程序竣事时会守候quartz相关的内容竣事
      wait-for-jobs-to-complete-on-shutdown: true
      # QuartzScheduler启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应纪录
      overwrite-existing-jobs: true
      # 这里居然是个map,搞得智能提醒都没有,佛了
      properties:
        org:
          quartz:
          	# scheduler相关
            scheduler:
              # scheduler的实例名
              instanceName: scheduler
              instanceId: AUTO
            # 持久化相关
            jobStore:
              class: org.quartz.impl.jdbcjobstore.JobStoreTX
              driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
              # 示意数据库中相关表是QRTZ_开头的
              tablePrefix: QRTZ_
              useProperties: false
            # 线程池相关
            threadPool:
              class: org.quartz.simpl.SimpleThreadPool
              # 线程数
              threadCount: 10
              # 线程优先级
              threadPriority: 5
              threadsInheritContextClassLoaderOfInitializingThread: true

4.4 注册周期性的准时义务

第1节中提到的第一个子需求是在天天0点执行的,是一个周期性的义务,义务内容也是确定的,以是直接在代码里注册JobDetail和Trigger的bean就可以了。固然,这些JobDetail和Trigger也是会被持久化到数据库里。

/**
 * Quartz的相关设置,注册JobDetail和Trigger
 * 注重JobDetail和Trigger是org.quartz包下的,不是spring包下的,不要导入错误
 */
@Configuration
public class QuartzConfig {

    @Bean
    public JobDetail jobDetail() {
        JobDetail jobDetail = JobBuilder.newJob(StartOfDayJob.class)
                .withIdentity("start_of_day", "start_of_day")
                .storeDurably()
                .build();
        return jobDetail;
    }

    @Bean
    public Trigger trigger() {
        Trigger trigger = TriggerBuilder.newTrigger()
                .forJob(jobDetail())
                .withIdentity("start_of_day", "start_of_day")
                .startNow()
                // 天天0点执行
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 * * ?"))
                .build();
        return trigger;
    }
}

builder类建立了一个JobDetail和一个Trigger并注册成为Spring bean。从第3节中摘录的官方文档中,我们已经知道这些bean会自动关联到调剂器上。需要注重的是JobDetail和Trigger需要设置组名和自己的名字,用来作为唯一标识。固然,JobDetail和Trigger的唯一标识可以相同,由于他们是差别的类。

Trigger通过cron表达式指定了义务执行的周期。对cron表达式不熟悉的同砚可以百度学习一下。

JobDetail里有一个StartOfDayJob类,这个类就是Job接口的一个实现类,内里界说了义务的详细内容,看一下代码:

@Component
public class StartOfDayJob extends QuartzJobBean {
    private StudentService studentService;

    @Autowired
    public StartOfDayJob(StudentService studentService) {
        this.studentService = studentService;
    }

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext)
            throws JobExecutionException {
        // 义务的详细逻辑
    }
}

这内里有一个小问题,上面用builder建立JobDetail时,传入了StartOfDayJob.class,按常理推测,应该是Quartz框架通过反射建立StartOfDayJob工具,再挪用executeInternal()执行义务。这样依赖,这个Job是Quartz通过反射建立的,纵然加了注解@Component,这个StartOfDayJob工具也不会被注册到ioc容器中,更不可能实现依赖的自动装配。

网上许多博客也是这么先容的。然则凭据我的现实测试,这样写可以完成依赖注入,但我还不知道它的实现原理。

4.5 注册无周期性的准时义务

第1节中提到的第二个子需求是学生请假,显然请假是不准时的,一次性的,而且不具有周期性。

4.5节与4.4节大要相同,然则有两点区别:

  • Job类需要获取到一些数据用于义务的执行;
  • 义务执行完成后删除Job和Trigger。

营业逻辑是在先生批准学生的请假申请时,向调剂器添加Trigger和JobDetail。

实体类:

public class LeaveApplication {
    @TableId(type = IdType.AUTO)
    private Integer id;
    private Long proposerUsername;
    @JsonFormat( pattern = "yyyy-MM-dd HH:mm",timezone="GMT+8")
    private LocalDateTime startTime;
    @JsonFormat( pattern = "yyyy-MM-dd HH:mm",timezone="GMT+8")
    private LocalDateTime endTime;
    private String reason;
    private String state;
    private String disapprovedReason;
    private Long checkerUsername;
    private LocalDateTime checkTime;

    // 省略getter、setter
}

Service层逻辑,主要的地方已在注释中说明。

@Service
public class LeaveApplicationServiceImpl implements LeaveApplicationService {
    @Autowired
    private Scheduler scheduler;
    
    // 省略其他方式与其他依赖

    /**
     * 添加job和trigger到scheduler
     */
    private void addJobAndTrigger(LeaveApplication leaveApplication) {
        Long proposerUsername = leaveApplication.getProposerUsername();
        // 建立请假最先Job
        LocalDateTime startTime = leaveApplication.getStartTime();
        JobDetail startJobDetail = JobBuilder.newJob(LeaveStartJob.class)
            	// 指界说务组名和义务名
                .withIdentity(leaveApplication.getStartTime().toString(),
                        proposerUsername + "_start")
                // 添加一些参数,执行的时刻用
                .usingJobData("username", proposerUsername)
                .usingJobData("time", startTime.toString())
                .build();
        // 建立请假最先义务的触发器
        // 建立cron表达式指界说务执行的时间,由于请假时间是确定的,以是年月日时分秒都是确定的,这也相符义务只执行一次的要求。
        String startCron = String.format("%d %d %d %d %d ? %d",
                startTime.getSecond(),
                startTime.getMinute(),
                startTime.getHour(),
                startTime.getDayOfMonth(),
                startTime.getMonth().getValue(),
                startTime.getYear());
        CronTrigger startCronTrigger = TriggerBuilder.newTrigger()
	            // 指定触发器组名和触发器名
                .withIdentity(leaveApplication.getStartTime().toString(),
                        proposerUsername + "_start")
                .withSchedule(CronScheduleBuilder.cronSchedule(startCron))
                .build();

        // 将job和trigger添加到scheduler里
        try {
            scheduler.scheduleJob(startJobDetail, startCronTrigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new CustomizedException("添加请假义务失败");
        }
    }
}

Job类逻辑,主要的地方已在注释中说明。

@Component
public class LeaveStartJob extends QuartzJobBean {
    private Scheduler scheduler;
    private SystemUserMapperPlus systemUserMapperPlus;

    @Autowired
    public LeaveStartJob(Scheduler scheduler,
                         SystemUserMapperPlus systemUserMapperPlus) {
        this.scheduler = scheduler;
        this.systemUserMapperPlus = systemUserMapperPlus;
    }

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext)
            throws JobExecutionException {
        Trigger trigger = jobExecutionContext.getTrigger();
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        // 将添加义务的时刻存进去的数据拿出来
        long username = jobDataMap.getLongValue("username");
        LocalDateTime time = LocalDateTime.parse(jobDataMap.getString("time"));

        // 编写义务的逻辑

        // 执行之后删除义务
        try {
            // 暂停触发器的计时
            scheduler.pauseTrigger(trigger.getKey());
            // 移除触发器中的义务
            scheduler.unscheduleJob(trigger.getKey());
            // 删除义务
            scheduler.deleteJob(jobDetail.getKey());
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}

5 总结

上文所述的内容应该可以知足绝大部分准时义务的需求。我在查阅网上的博客之后,发现大部分博客里先容的Quartz使用照样停留在Spring阶段,设置也都是通过xml,因此我在实现了功效以后,将整个历程总结了一下,留给需要的人以及以后的自己做参考。

总体上来说,Quartz实现准时义务照样异常利便的,与SpringBoot整合之后设置也异常简朴,是实现准时义务的不错的选择。

5.2 小坑1

在IDEA2020.1版本里使用SpringBoot与Quartz时,报错找不到org.quartz程序包,然则依赖内里明显有org.quartz,类里的import也没有报错,还可以通过Ctrl+鼠标左键直接跳转到响应的类里。后面我用了IDEA2019.3.4就不再有这个错误。那么就是新版IDEA的BUG了。

保定招聘:SpringBoot集成Quartz实现准时义务 第1张

本文由博客群发一文多发等运营工具平台 OpenWrite 公布

,

Sunbet

Sunbet www.698739.com Sunbet是进入Sunbet的主力站点。Sunbet开放Sunbet会员开户网址、Sunbet代理开户、Sunbet手机版下载、Sunbet电脑客户端下载等业务。www.sunbet.us值得您的信赖!

本文链接:https://www.zhaoyuan777.com/post/774.html

网友评论

最新评论

  • 联博API接口 09/21 说:

    Allbet官网欢迎进入Allbet官网(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。一句话夸不完

  • 联博API接口 09/21 说:

    Allbet官网欢迎进入Allbet官网(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。一句话夸不完

  • 联博统计 09/20 说:

    Allbet手机版下载欢迎进入Allbet手机版下载(www.aLLbetgame.us):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。不会这样吧

  • UG环球APP下载 09/19 说:

    欧博Allbet欢迎进入欧博Allbet官网(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。biu~爱心发射

  • 环球UG手机版下载 09/19 说:

    欧博客户端下载欢迎进入欧博客户端下载(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。可以再练练

  • UG环球开户 09/18 说:

    欧博APP下载欢迎进入欧博APP下载(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。今天下雨,躲在家里看

  • UG环球开户 09/18 说:

    欧博APP下载欢迎进入欧博APP下载(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。今天下雨,躲在家里看

  • 环球UG充值 09/17 说:

    欧博开户网址欢迎进入欧博开户网址(Allbet Gaming):www.aLLbetgame.us,欧博网址开放会员注册、代理开户、电脑客户端下载、苹果安卓下载等业务。太有心意了