springboot整合quartz项目使用案例

 更新时间:2023年05月13日 10:31:27   作者:小lee学编程  
quartz是一个定时调度的框架,就目前市场上来说,其实有比quartz更优秀的一些定时调度框架,不但性能比quartz好,学习成本更低,而且还提供可视化操作定时任务,这篇文章主要介绍了springboot整合quartz项目使用(含完整代码),需要的朋友可以参考下

前言:quartz是一个定时调度的框架,就目前市场上来说,其实有比quartz更优秀的一些定时调度框架,不但性能比quartz好,学习成本更低,而且还提供可视化操作定时任务。例如xxl-Job,elastic-Job这两个算是目前工作中使用比较多的定时调度框架了,适配于分布式的项目,性能也是很优秀。这是很多人就很疑惑,既然这样我们为什么还要了解学习quartz呢?我个人觉得学习quartz有两方面,首先xxl-Job,elastic-Job这些框架都是基于quartz的基础上二次开发的,学习quartz更有利于我们加强理解定时调度。第二方面就是工作需求,有一些传统互联网公司还是有很多项目是使用quartz来完成定时任务的开发的,不懂quartz的话,老板叫你写个定时任务都搞不定。

1. quartz的基础概念

在这里插入图片描述

有上图可以看到,一个job可以给多个jobDetail封装,一个jobDetail可以给trigger来配置规则,但是一个trigger只能装配一个jobDetail。

scheduler:可以理解为定时任务的工作容器或者说是工作场所,所有定时任务都是放在里面工作,可以开启和停止。

trigger:可以理解为是定时任务任务的工作规则配置,例如说,没个几分钟调用一次,或者说指定每天那个时间点执行。

jobDetail:定时任务的信息,例如配置定时任务的名字,群组之类的。

job:定时任务的真正的业务处理逻辑的地方。

2. quartz的简单使用

这是quartz的api使用,在官网直接提供使用例子,但是在工作中用不到这种方式的

地址:https://www.quartz-scheduler.org/documentation/quartz-2.3.0/quick-start.html

public class QuartzTest {
    public static void main(String[] args) throws Exception{
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.start();
            JobDetail job = newJob(HelloJob.class)
                    .withIdentity("job1", "group1")
                    .build();
            Trigger trigger = newTrigger()
                    .withIdentity("trigger1", "group1")
                    .startNow()
                    .withSchedule(simpleSchedule()
                            .withIntervalInSeconds(2)
                            .repeatForever())
                    .build();
            scheduler.scheduleJob(job, trigger);
            TimeUnit.SECONDS.sleep(20);
            scheduler.shutdown();
        } catch (SchedulerException se) {
            se.printStackTrace();
        }
    }
}

3. quartz与springboot的整合使用

在官网中介绍了,只要你引用了quartz的依赖后,springboot会自适配调度器。当然我们也可以新建bean,修改SchedulerFactoryBean的一些默认属性值。

使用javaBean方式按实际业务需求初始化SchedulerFactoryBean(可以不要,就用默认SchedulerFactoryBean

@Configuration
public class QuartzConfiguration {
    // Quartz配置文件路径
    private static final String QUARTZ_CONFIG = "config/quartz.properties";
    @Value("${task.enabled:true}")
    private boolean enabled;
    @Autowired
    private DataSource dataSource;
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setDataSource(dataSource);
        // 设置加载的配置文件
        schedulerFactoryBean.setConfigLocation(new ClassPathResource(QUARTZ_CONFIG));
        // 用于quartz集群,QuartzScheduler 启动时更新己存在的Job
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        schedulerFactoryBean.setStartupDelay(5);// 系统启动后,延迟5s后启动定时任务,默认为0
        // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        // SchedulerFactoryBean在初始化后是否马上启动Scheduler,默认为true。如果设置为false,需要手工启动Scheduler
        schedulerFactoryBean.setAutoStartup(enabled);
        return schedulerFactoryBean;
    }
}

要使用quartz实现定时任务,首先要新建一个Job,在springboot中,新建的Job类要继承QuartzJobBean

public class HelloJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context)  {
        StringJoiner joiner = new StringJoiner(" | ")
                .add("---HelloJob---")
                .add(context.getTrigger().getKey().getName())
                .add(DateUtil.formatDate(new Date()));
        System.out.println(joiner);
    }
}

创建jobDetail和Trigger来启动定时任务,有两种方式可以实现,本质上就是创建jobDetail和Trigger

方式一:为对应的Job创建JobDetail和Trigger,这种方式有两个注意的地方,jobDetail一定要设置为可持久化.storeDurably(),Trigger创建要用.forJob(“helloJob”),要与JobDetail定义的相同。

@Component
public class HelloJobDetailConfig {
    @Bean
    public JobDetail helloJobDetail(){
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("helloJob")
                .storeDurably()
                .usingJobData("data", "保密信息")
                .build();
        return jobDetail;
    }
    @Bean
    public Trigger helloJobTrigger(){
        Trigger trigger = TriggerBuilder.newTrigger()
                .forJob("helloJob")
                .withSchedule(simpleSchedule()
                        .withIntervalInSeconds(3)
                        .repeatForever())
                .build();
        return trigger;
    }
}

方式二:在注入Bean之前初始化创建JobDetail和Trigger,然后使用Scheduler来调用,跟原生API调用差不多。

@Component
public class HelloJobDetailConfig2 {
    @Autowired
    private Scheduler scheduler;
    @PostConstruct
    protected void InitHelloJob() throws Exception {
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("helloJob")
//                .storeDurably()
                .usingJobData("data", "保密信息")
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("helloTrigger")
                .withSchedule(simpleSchedule()
                        .withIntervalInSeconds(3)
                        .repeatForever())
                .build();
        scheduler.scheduleJob(jobDetail,trigger);
    }
}

4. quartz的持久化

在这里插入图片描述

quartz持久化有两种存储,一般情况下quartz相关的表和业务表是放在同一个数据库里的。但是如果考虑性能问题的话,就要配多数据源,业务表单独一个库,quartz相关的表放在一个库。

https://docs.spring.io/spring-boot/docs/2.3.12.RELEASE/reference/html/spring-boot-features.html#boot-features-quartz

spring官网说明,默认情况下,使用内存中的JobStore。但是,如果应用程序中有DataSourcebean,并且spring.quartz是可用的,则可以配置基于JDBC的存储。将相应地配置作业存储类型属性。第二个配置,每次启动先删除表数据再重新创建(在实际生产中,个人更倾向于拿dml来手动创建表,这个值设置为never)。在quartz的jar包里这个路径下有不同数据库的dml:org.quartz.impl.jdbcjobstore

spring.quartz.job-store-type=jdbc

spring.quartz.jdbc.initialize-schema=never

另外一种方式:

要让Quartz使用DataSource而不是应用程序的主DataSource,请声明DataSourcebean,并用@QuartzDataSource注释其@bean方法。这样做可以确保SchedulerFactoryBean和模式初始化都使用Quartz特定的DataSource

@Configuration
public class QuartzDataSourceConfig {
    @Bean
    @QuartzDataSource
    public DataSource quartzDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false");
        return dataSource;
    }
}

还有一点需要注意:当jobbean已经注入spring容器后,下次不用需要再注入,把@Component注释掉。

5. quartz的misfire策略

**misfire:**到了任务触发时间点,但是任务没有被触发

原因:- 使用@DisallowConcurrentExecution注解,而且任务的执行时间>任务间隔

-线程池满了,没有资源执行任务

-机器宕机或者认为停止,果断时间恢复运行。

@DisallowConcurrentExecution:这个是比较常用的注解,证上一个任务执行完后,再去执行下一个任务,不会允许任务并行执行。

@PersistJobDataAfterExecution:任务执行完后,会持久化保留数据到下次 执行

针对不同的ScheduleBuilder,可以设置不同的失火策略,SimpleScheduleBuilder和非SimpleScheduleBuilder,

SimpleScheduleBuilder有六种,而非SimpleScheduleBuilder有三种,在实际工作中我们使用的比较的是CronScheduleBuilder.

.withMisfireHandlingInstructionIgnoreMisfires()
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1
所有未触发的执行都会立即执行,然后触发器再按计划运行。

.withMisfireHandlingInstructionFireAndProceed()
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1
立即执行第一个错误的执行并丢弃其他(即所有错误的执行合并在一起),也就是说无论错过了多少次触发器的执行,都只会立即执行一次,然后触发器再按计划运行。(默认的失火策略)

.withMisfireHandlingInstructionDoNothing()
MISFIRE_INSTRUCTION_DO_NOTHING = 2
所有未触发的执行都将被丢弃,然后再触发器的下一个调度周期按计划运行。

6、总结

关于quartz还有一个很重要的点就是corn表达式,这个个人认为没必要死记硬背,实在不会写的,上网找corn表达式在线转换就可以了。

一个简单demo的代码地址:https://gitee.com/gorylee/quartz-demo
生产项目中quartz的配置使用代码地址:https://gitee.com/gorylee/learnDemo/tree/master/quartzDemo

到此这篇关于springboot整合quartz项目使用(含完整代码)的文章就介绍到这了,更多相关springboot整合quartz内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java.sql.SQLException问题解决以及注意事项

    java.sql.SQLException问题解决以及注意事项

    这篇文章主要给大家介绍了关于java.sql.SQLException问题解决以及注意事项的相关资料,这个问题其实很好解决,文中通过图文将解决的办法介绍的很详细,需要的朋友可以参考下
    2023-07-07
  • 深入聊聊Java内存泄露问题

    深入聊聊Java内存泄露问题

    所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中,下面这篇文章主要给大家介绍了关于Java内存泄露问题的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-04-04
  • 如何解决springmvc文件下载,内容损坏的问题

    如何解决springmvc文件下载,内容损坏的问题

    这篇文章主要介绍了解决springmvc文件下载,内容损坏的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • Java编程实现时间和时间戳相互转换实例

    Java编程实现时间和时间戳相互转换实例

    这篇文章主要介绍了什么是时间戳,以及Java编程实现时间和时间戳相互转换实例,具有一定的参考价值,需要的朋友可以了解下。
    2017-09-09
  • Springboot整合Swagger3全注解配置(springdoc-openapi-ui)

    Springboot整合Swagger3全注解配置(springdoc-openapi-ui)

    本文主要介绍了Springboot整合Swagger3全注解配置(springdoc-openapi-ui),文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • java中的 HashMap 的加载因子是0.75原理探讨

    java中的 HashMap 的加载因子是0.75原理探讨

    在Java中,HashMap是一种常用的数据结构,用于存储键值对,它的设计目标是提供高效的插入、查找和删除操作,在HashMap的实现中,加载因子(Load Factor)是一个重要的概念,本文将探讨为什么Java中的HashMap的加载因子被设置为0.75
    2023-10-10
  • Java 类加载机制详细介绍

    Java 类加载机制详细介绍

    这篇文章主要介绍了Java 类加载机制详细介绍的相关资料,需要的朋友可以参考下
    2017-05-05
  • Eclipse、MyEclipse 导入svn项目具体步骤

    Eclipse、MyEclipse 导入svn项目具体步骤

    这篇文章主要介绍了Eclipse、MyEclipse 导入svn项目具体步骤的相关资料,需要的朋友可以参考下
    2016-10-10
  • spring中actuator监视器配置详解

    spring中actuator监视器配置详解

    这篇文章主要介绍了spring中actuator监视器配置详解,actuator主要是完成微服务的监控,完成监控治理,可以查看微服务间的数据处理和调用,当它们之间出现了异常,就可以快速定位到出现问题的地方,需要的朋友可以参考下
    2023-09-09
  • Java文件与Base64之间的转化方式

    Java文件与Base64之间的转化方式

    这篇文章介绍了如何使用Java将文件(如图片、视频)转换为Base64编码,以及如何将Base64编码转换回文件,通过提供具体的工具类实现,作者希望帮助读者更好地理解和应用这一过程
    2025-02-02

最新评论