Springboot整合定时任务quartz(非集群)


前言

工具篇-- 定时任务quartz 我们已经知道了quartz 的基本特性和简单使用,在项目开发中我们通常都是集成到springboot 项目中。


一、Springboot 整合

1.1 Springboot 初步整合quartz

1.1 jar 引入:

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-quartz -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

1.2 添加任务:

1.2.1 方式1 PostConstruct 注入任务:

JobInit :

import com.example.springmvctest.job.quartz.MyJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

// 定义 JobInit  为一个bean 从而可以被spring 管理
@Component
public class JobInit {

    @Autowired
    private Scheduler scheduler;

	// JobInit  这个bean 在初始化之后调用的方法
    @PostConstruct
    public  void  job(){
        // 每次执行 都生成新的  MyJob 实例,避免并发情境下,多个线程共用一个MyJob 的实例
        JobDetail jobDetail = JobBuilder.newJob(QuartzTest.class)
                .usingJobData("job","jobDetail")
                .usingJobData("name","jobDetail")
                .usingJobData("count",0)
                .withIdentity("job","group1").build();

        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1","trigger1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)
                        .repeatForever())
                .usingJobData("trigger","trigger")
                .usingJobData("name","trigger")
                .build();


        try {
            scheduler.scheduleJob(jobDetail,trigger);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }

    }
}

任务执行:
(1) 任务定义:
QuartzTest :

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.StringJoiner;

public class QuartzTest extends QuartzJobBean {
    @Autowired
    private HelloService helloService;
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        System.out.println("\"job 执行\" = " + "job 执行" + sdf.format(new Date()));
        StringJoiner outStr = new StringJoiner("")
                .add("QuartzTest 执行")
                .add(sdf.format(new Date()))
                .add(Thread.currentThread().getName())
                .add(context.getTrigger().getKey().getName())
                .add(helloService.toString())
                .add(helloService.hello());

        System.out.println(outStr);
    }
}

(2) HelloService :

import org.springframework.stereotype.Service;

@Service
public class HelloService {

    public String hello(){
        return "hello";
    }
}
1.2.2 方式2 @Bean 注入任务:

JobConfigure :中定义的JobDetail 和Trigger 会自动被 scheduler 关联起来

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JobConfigure {

    @Bean
    public JobDetail jobDetail1() {
        return JobBuilder.newJob(QuartzTest.class)
                .usingJobData("job", "jobDetail")
                .usingJobData("name", "jobDetail")
                .usingJobData("count", 0)
                .storeDurably()
                .withIdentity("jobConfigure", "group1").build();
    }

    @Bean
    public Trigger trigger1() {
        return TriggerBuilder.newTrigger()
                .withIdentity("triggerConfigure", "trigger1")
                .forJob("jobConfigure","group1")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)
                        .repeatForever())
                .usingJobData("trigger", "trigger")
                .usingJobData("name", "trigger")
                .build();
    }

    @Bean
    public JobDetail jobDetail2() {
        return JobBuilder.newJob(QuartzTest.class)
                .usingJobData("job", "jobDetail2")
                .usingJobData("name", "jobDetail2")
                .usingJobData("count", 0)
                .storeDurably()
                .withIdentity("jobConfigure2", "group1").build();
    }

    @Bean
    public Trigger trigger2() {
        return TriggerBuilder.newTrigger()
                .withIdentity("triggerConfigure2", "trigger2")
                .forJob("jobConfigure2","group1")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2)
                        .repeatForever())
                .usingJobData("trigger", "trigger2")
                .usingJobData("name", "trigger2")
                .build();
    }
}

在这里插入图片描述

二、quartz持久化:

如果不将Job 进行持久化,那么Job 只存在于内存中,一旦项目重启,之前的任务状态将全部丢失,所以quartz 还支持通过关系型数据库将任务持久化:

2.1 mysql 引入:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>
<!-- 分页 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.1.6</version>
</dependency>

2.2 业务共用一个数据源:

业务系统和定时任务使用同一个数据源。

2.2.1 配置jdbc datasource:

(1)HikariBaseConfig:

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Configuration;

/**
 * 线程池
 */
@Configuration
public class HikariBaseConfig {

    @Value("${spring.datasource.hikari.pool-name}")
    private String poolName;
    @Value("${spring.datasource.hikari.maximum-pool-size}")
    private Integer maximumPoolSize;
    @Value("${spring.datasource.hikari.connection-timeout}")
    private Long connectionTimeout;
    @Value("${spring.datasource.hikari.minimum-idle}")
    private Integer minimumIdle;
    @Value("${spring.datasource.hikari.max-lifetime}")
    private Long maxLifetime;
    @Value("${spring.datasource.hikari.connection-test-query}")
    private String connectionTestQuery;


    public HikariDataSource getDataSource(String driverClassName, String url, String username, String password){
        HikariDataSource hikariDataSource = DataSourceBuilder.create().type(HikariDataSource.class).driverClassName(driverClassName).username(username).url(url).password(password).build();
        hikariDataSource.setConnectionTestQuery(connectionTestQuery);
        hikariDataSource.setMaxLifetime(maxLifetime);
        hikariDataSource.setMinimumIdle(minimumIdle);
        hikariDataSource.setConnectionTimeout(connectionTimeout);
        hikariDataSource.setPoolName(poolName);
        hikariDataSource.setMaximumPoolSize(maximumPoolSize);
        return hikariDataSource;
    }

}

(2)DataSourceConfig:


//import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
//import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.github.pagehelper.PageHelper;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * @Description TODO
 * @Date 2021/11/18 11:00
 * @Author lgx
 * @Version 1.0
 */
// 标明注解
@Configuration
// 开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactional 便可
@EnableTransactionManagement
// 配置xml 扫描文件位置
@MapperScan(basePackages = {"com.example.springmvctest.mapper"}, sqlSessionFactoryRef = "bluegrassSqlSessionFactory")
public class DataSourceConfig {
    @Value("${spring.datasource.bluegrass.jdbc-url}")
    private String url;

    @Value("${spring.datasource.bluegrass.driver-class-name}")
    private String driverClassName;

    @Value("${spring.datasource.bluegrass.username}")
    private String username;

    @Value("${spring.datasource.bluegrass.password}")
    private String password;

    @Autowired
    private HikariBaseConfig hikariBaseConfig;

    @Primary
    @Bean(name = "bluegrassDataSource")
    public DataSource masterDataSource() {
        return hikariBaseConfig.getDataSource(driverClassName, url, username, password);
    }

    @Primary
    @Bean
    public JdbcTemplate jdbcTemplate(@Qualifier("bluegrassDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Primary
    @Bean(name = "bluegrassSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("bluegrassDataSource") DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mapper/quartz/**/*.xml"));
// 全局字段创建人/更新人/创建时间/更新时间 字段的填充
//        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setMetaObjectHandler(new BluegrassMetaHandler());
//        sessionFactoryBean.setGlobalConfig(globalConfig);
        // sessionFactoryBean.setPlugins(new Interceptor[]{pageHelper()});
        Interceptor[] plugins = {paginationInterceptor()};
        sessionFactoryBean.setPlugins(plugins);
        return sessionFactoryBean.getObject();
    }

    @Primary
    @Bean(name = "bluegrassSqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("bluegrassSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    /**
     * 事务管理
     *
     * @param dataSource
     * @return
     */
    @Primary
    @Bean(name = "bluegrassTransactionManager")
    public DataSourceTransactionManager transactionManager(@Qualifier("bluegrassDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 分页插件
     */
    @Primary
    @Bean
    public PageHelper pageHelper() {
        //分页插件
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("offsetAsPageNum", "true");
        properties.setProperty("rowBoundsWithCount", "true");
        properties.setProperty("reasonable", "true");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("returnPageInfo", "check");
        properties.setProperty("params", "count=countSql");
        pageHelper.setProperties(properties);
        return pageHelper;
    }

    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor().setDialectType("mysql");
    }

}

(3)数据源配置:
application.yml:

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource  #数据源类型
    hikari:
      pool-name: KevinHikariPool  #连接池名称,默认HikariPool-1
      maximum-pool-size: 20   #最大连接数,小于等于0会被重置为默认值10;大于零小于1会被重置为minimum-idle的值
      connection-timeout: 60000 #连接超时时间:毫秒,小于250毫秒,否则被重置为默认值30秒
      minimum-idle: 10  #最小空闲连接,默认值10,小于0或大于maximum-pool-size,都会重置为maximum-pool-size
      idle-timeout: 500000   # 只有空闲连接数大于最大连接数且空闲时间超过该值,才会被释放
      max-lifetime: 600000   #连接最大存活时间.不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短
      connection-test-query: SELECT 1   #连接测试查询
    bluegrass:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3406/quartz?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useAffectedRows=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
      username: root
      password: ddsoft

2.2.2 Springboot 整合quartz 持久化:

在application.yml: 增加 quartz 持久化参数即可:

spring:
  # quartz 定义
  quartz:
  	 # 持久化类型为jdbc
    job-store-type: jdbc
	# 定义任务的初始化类型
    jdbc:
      initialize-schema: always
#      initialize-schema: never

注意第一次启动项目 initialize-schema 可以设置为 always,进行数据库quartz 对应表的生成,后续启动项目 改值可以调整为 never (不出初始化),该参数可以在 三, 扩展 章节详细了解;

2.3 Springboot 整合quartz 持久化(独立数据源)

(1)在application.yml: 增加 quartz 持久化单独的数据源:

spring:
	quartz:
	     driver-class-name: com.mysql.cj.jdbc.Driver
	     jdbc-url: jdbc:mysql://localhost:3406/quartz-oneself?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useAffectedRows=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
	     username: root
	     password: ddsoft

(2)标识quartz 数据源:

QuartzDataSourceConfig


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.quartz.QuartzDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class QuartzDataSourceConfig {

    @Value("${spring.datasource.quartz.jdbc-url}")
    private String url;

    @Value("${spring.datasource.quartz.driver-class-name}")
    private String driverClassName;

    @Value("${spring.datasource.quartz.username}")
    private String username;

    @Value("${spring.datasource.quartz.password}")
    private String password;

    @Autowired
    private HikariBaseConfig hikariBaseConfig;

    @Bean
    // 标识quartz 数据源
    @QuartzDataSource
    public DataSource QuartzDataSource() {
        return hikariBaseConfig.getDataSource(driverClassName, url, username, password);
    }
}


三、 扩展:

3.1 initialize-schema 初始化:

初始化的方式,其取值可以是alwaysneverembedded

  • always:表示当Quartz启动时,它始终会尝试自动初始化数据库表结构。如果表已经存在,Quartz将首先删除现有的表,然后创建新的表。这样可以确保数据库表结构始终与Quartz的期望一致。
  • never:表示Quartz在启动时不会尝试自动初始化数据库表结构。这意味着您必须手动创建和维护Quartz所需的表结构。
  • embedded:表示Quartz会自动检查数据库中的表结构。如果表已经存在且符合预期的结构,Quartz将继续使用现有的表。否则,它会尝试自动创建所需的表结构。

如果您使用Spring框架与Quartz集成,可以在Spring的配置文件中使用以下属性来设置org.quartz.jobStore.initialize-schema

spring.quartz.properties.org.quartz.jobStore.initialize-schema=always

通过根据需要设置org.quartz.jobStore.initialize-schema参数,可以控制Quartz在启动时如何处理数据库表结构的初始化。

四、总结:

Springboot 通过引入quartz 对应的start jar 包,随后就可以在业务中定义相应的job 和 trigger 然后使用调度器进行关联后,就可以完成任务的调度。

五、参考:

1 spring quartz 参数配置参考;

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,下面是关于使用Spring BootQuartz实现定时任务的简介: Quartz是一个流行的Java定时任务框架,可以在应用程序中执行各种定时任务,如定期备份、数据抽取和数据分析等。而Spring Boot是一个快速开发框架,提供了方便的集成Quartz的方式。 要使用Spring BootQuartz实现定时任务,首先需要在pom.xml文件中添加QuartzSpring Boot Quartz的依赖项。然后,定义一个定时任务,可以使用注解@Scheduled来指定任务的执行时间。例如: ```java @Component public class MyScheduler { @Scheduled(cron = "0 0/10 * * * ?") public void myTask() { //执行定时任务的代码 } } ``` 上述代码表示每隔10分钟执行一次myTask()方法。然后,在Spring Boot的主类中,使用@EnableScheduling注解来开启定时任务的支持。例如: ```java @SpringBootApplication @EnableScheduling public class MyApp { public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } } ``` 最后,启动应用程序,定时任务将按照预定时间自动执行。如果需要更高级的定时任务控制,还可以使用Quartz的其他功能,如JobDetail和Trigger等。 ### 回答2: SpringBoot是一个开源的Java开发框架,它提供了很多有用的工具和插件,其中之一便是定时任务quartzquartz是一款功能强大的开源调度框架,它提供了简单易用的任务调度机制,支持多线程和分布式部署,可以满足大部分的调度需求。 在SpringBoot中,我们可以很方便地使用quartz来实现定时任务。以下是使用SpringBootquartz实现定时任务的基本步骤: 1. 在pom.xml文件中添加quartz的依赖项: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> ``` 2. 创建一个任务类,实现Job接口,并实现execute方法来定义任务逻辑: ``` @Component public class MyTask implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { // 定时任务的执行逻辑 } } ``` 3. 在配置文件中定义任务调度器,并为任务分配cron表达式: ``` spring: quartz: job-store-type: jdbc properties: org.quartz.scheduler.instanceName: MyScheduler org.quartz.threadPool.threadCount: 5 job-details: myJob: durability: true requestsRecovery: true trigger-details: myTrigger: cron: 0 0/1 * * * ? job-name: myJob job-data-map: name: world ``` 4. 在任务执行类中,使用@Scheduled注解来指定任务的执行时间: ``` @Component public class MyTask { @Scheduled(cron = "0 0/1 * * * ?") public void doTask(){ // 定时任务的执行逻辑 } } ``` 以上4种方法都是使用SpringBootquartz实现定时任务的简单示例,根据实际需求可以进行相应调整和扩展。总的来说,使用springbootquartz实现定时任务常方便,能够让我们更加轻松地管理、调度和执行任务,提高开发效率和质量。 ### 回答3: Spring Boot是一款快速构建基于Spring应用的工具,可帮助简化开发和部署。在Spring Boot中,与Quartz相比,Scheduled定时任务通常是首选的。但是,Quartz比Scheduled更灵活、功能更强大、配置更灵活,因此在一些特殊情况下,使用Quartz进行定时任务调度是比较必要的。 Quartz是用Java语言编写的一个开源的调度框架,其主要用于在一个预定义的时间间隔内重复执行某个任务,或者在特定时间点执行某个任务。Quartz提供了众多功能,比如支持分布式定时任务管理、支持动态创建/删除任务、支持时间表达式、状态存储、监控和事件触发等等。 Spring Boot集成了Quartz常容易,只需要在Spring Boot项目中添加Quartz相关依赖,在Spring Boot配置文件中增加Quartz配置即可。以下是一个完整的Spring Boot集成Quartz的示例代码: 1.在pom.xml中添加QuartzSpring Boot Starter Web依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> ``` 2.在配置文件中增加Quartz相关配置: ``` spring.quartz.job-store-type=memory spring.quartz.properties.org.quartz.threadPool.threadCount=10 spring.quartz.properties.org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore ``` 3.编写定时任务处理类: ``` @Component public class JobScheduler { @Autowired private Scheduler scheduler; @Scheduled(cron = "0 0/1 * * * ?") public void doSomething() { JobDetail jobDetail = buildJobDetail(); Trigger trigger = buildJobTrigger(jobDetail); try { scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException e) { e.printStackTrace(); } } private JobDetail buildJobDetail() { JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("key", "value"); return JobBuilder.newJob(Job.class) .withIdentity(UUID.randomUUID().toString(), "job-group") .withDescription("sample job") .usingJobData(jobDataMap) .storeDurably(true) .build(); } private Trigger buildJobTrigger(JobDetail jobDetail) { return TriggerBuilder.newTrigger() .forJob(jobDetail) .withIdentity(UUID.randomUUID().toString(), "trigger-group") .withDescription("sample trigger") .withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 * * * ?")) .build(); } } ``` 虽然Quartz需要对定时任务进行配置,但是它提供了更为灵活的条件和任务调度,常适合在实际生产环境中使用。总之,使用Spring Boot集成Quartz可以常方便地实现定时任务的调度,既简单又强大,可以大大提高应用的效率和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值