SpringBoot2.0基于数据库集成quartz,集群部署,增删改查,实现同一定时任务同一时间多实例每次只运行一次

本例使用quartz持久化数据库的方式,结合JPA,简单写几个web接口,演示集群状态下定时任务在页面的增删改查,验证同一定时任务同一时间执行的唯一性,避免多实例集群部署导致同一个定时任务执行多次。

springboot版本如下,自动引用的quartz版本为2.3.0,数据库使用mysql

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

1、下载sql文件

1.1、下载quartz对应版本的sql文件

官方网址:http://www.quartz-scheduler.org/downloads/

在这里插入图片描述

1.2、导入sql文件到数据库

quartz-2.3.0-distribution\quartz-2.3.0-SNAPSHOT\src\org\quartz\impl\jdbcjobstore
下载后解压文件,通过以上路径找到对应的sql文件,导入数据库
在这里插入图片描述
导入成功可以看到新增如下表
在这里插入图片描述

1.3、各表代表意义

在这里插入图片描述

2、pom依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.Springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--mysql链接依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-jdbc</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP-java7</artifactId>
            <version>2.4.13</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3、添加配置文件

3.1、application.yml

server:
  port: 8081

logging:
  file: logback.xml

spring:
  dataSource:
    url: jdbc:mysql://localhost:3306/quartz?characterEncoding=utf-8&autoReconnect=true&allowMultiQueries=true&useSSL=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC
    username: root
    password: ******
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      minimum-idle: 5
      maximum-pool-size: 15
      idle-timeout: 30000
      pool-name: DatebookHikariCP
      max-lifetime: 1800000
      connection-timeout: 30000
      connection-test-query: 'SELECT 1'

  jpa:
    properties:
      hibernate:
        hbm2ddl:
          auto: validate
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        format_sql: true
  show-sql: true

3.2、quartz.properties

#quartz集群配置
#调度标识名 集群中每一个实例都必须使用相同的名称
org.quartz.scheduler.instanceName=DefaultQuartzScheduler
#ID设置为自动获取 每一个必须不同
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.makeSchedulerThreadDaemon=true
#线程池的实现类(一般使用SimpleThreadPool即可满足需求)
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
#指定在线程池里面创建的线程是否是守护线程
org.quartz.threadPool.makeThreadsDaemons=true
#指定线程数,至少为1(无默认值)
org.quartz.threadPool.threadCount:20
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority:5
#数据保存方式为数据库持久化
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#表的前缀,默认QRTZ_
org.quartz.jobStore.tablePrefix=QRTZ_
#是否加入集群
org.quartz.jobStore.isClustered=true
# 信息保存时间 默认值60秒
org.quartz.jobStore.misfireThreshold=25000

3.3、日志配置文件logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
    <property name="LOG_HOME" value="/data/button/springboot" />

    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出,%d:日期;%thread:线程名;%-5level:级别,从左显示5个字符宽度;%msg:日志消息;%n:换行符 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -%msg%n</pattern>
        </encoder>
    </appender>
    <!-- 按照每天生成日志文件 -->
    <appender name="FILE"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/springboot_button.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名 -->
            <FileNamePattern>
                ${LOG_HOME}/springboot_button.log.%d{yyyy-MM-dd}.%i.log
            </FileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 日志文件最大size -->
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出,%d:日期;%thread:线程名;%-5level:级别,从左显示5个字符宽度;%msg:日志消息;%n:换行符 -->
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} -%msg%n</pattern>
        </encoder>
    </appender>

    <!-- 日志输出级别 -->
    <root level="ERROR">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

4、代码

4.1、添加quartz配置类

类QuartzConfigure

import org.quartz.Trigger;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

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


/**
 * @author tom
 * @version V1.0
 * @date 2020/10/5 14:51
 */
@Configuration
public class QuartzConfigure {

    private static final String QUARTZ_CONFIG = "/quartz.properties";

    @Autowired
    @Qualifier(value = "dataSource")
    private DataSource dataSource;

    /**
     * 读取Quartz配置属性
     * @return
     * @throws IOException
     */
    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource(QUARTZ_CONFIG));
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }

    /**
     * JobFactory与schedulerFactoryBean中的JobFactory相互依赖,注意bean的名称
     * 在这里为JobFactory注入了Spring上下文
     *
     * @param applicationContext
     * @return
     */
    @Bean
    public JobFactory buttonJobFactory(ApplicationContext applicationContext) {
        AutoWiredSpringBeanToJobFactory jobFactory = new AutoWiredSpringBeanToJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    }

    /**
     *
     * @param jobFactory  为SchedulerFactory配置JobFactory
     * @param cronJobTrigger
     * @return
     * @throws IOException
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, Trigger... cronJobTrigger) throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setJobFactory(jobFactory);
        factory.setOverwriteExistingJobs(true);
        factory.setAutoStartup(true); // 设置自行启动
        factory.setQuartzProperties(quartzProperties());
        factory.setTriggers(cronJobTrigger);
        factory.setDataSource(dataSource);// 使用自定义的dataSource替换quartz的dataSource
        return factory;
    }

}

类AutoWiredSpringBeanToJobFactory

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

/**
 * @author tom
 * @version V1.0
 * @date 2020/10/5 14:54
 */
public class AutoWiredSpringBeanToJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
    private transient AutowireCapableBeanFactory beanFactory;

    @Override
    public void setApplicationContext(final ApplicationContext context) {
        beanFactory = context.getAutowireCapableBeanFactory();
    }

    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
        final Object job = super.createJobInstance(bundle);
        beanFactory.autowireBean(job);
        return job;
    }
}

4.2、model类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

/**
 * @author tom
 * @version V1.0
 * @date 2020/10/5 18:32
 */
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ScheduleInfo {

    @Id
    @GeneratedValue
    private Long id;

    private String jobDetailName;

    private String jobDetailGroup;

    private String triggerName;

    private String triggerGroup;

    private Integer executeCount;

    public ScheduleInfo(String jobDetailName,String jobDetailGroup,String triggerName,
                      String triggerGroup,Integer executeCount){
        this.jobDetailName = jobDetailName;
        this.jobDetailGroup = jobDetailGroup;
        this.triggerName = triggerName;
        this.triggerGroup = triggerGroup;
        this.executeCount = executeCount;
    }

}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author tom
 * @version V1.0
 * @date 2020/10/4 15:18
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Response<T> {

    Integer code;

    String message;

    T result;

    public Response (String message,T result){
        this.code = 200;
        this.message = message;
        this.result = result;
    }

}

4.3、数据库操作类

import com.example.quartzdemo.model.ScheduleInfo;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * @author tom
 * @version V1.0
 * @date 2020/10/5 18:38
 */
public interface QuartzInfoRepository extends JpaRepository<ScheduleInfo,Long> {

    ScheduleInfo findByJobDetailName(String jobDetailName);

    void deleteByJobDetailName(String jobDetailName);

}

4.4、quartz增删改查类

import com.example.quartzdemo.dao.QuartzInfoRepository;
import com.example.quartzdemo.model.ScheduleInfo;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * 实现定时任务的增删改查
 * @author tom
 * @version V1.0
 * @date 2020/10/4 14:59
 */
@Component
public class QuartzManager {
    //任务组名
    public static final String JOB_GROUP_NAME = "cron_group";
    //触发器组名
    public static final String TRIGGER_GROUP_NAME = "cron_trigger";
    //触发器组名
    public static final String DEFAULT_GROUP_NAME = "DEFAULT";
    //调度工厂
    @Autowired
    private SchedulerFactoryBean schedulerFactory;
    @Autowired
    QuartzInfoRepository quartzInfoRepository;


    public Scheduler getScheduled(){
        return schedulerFactory.getScheduler();
    }

    /**
     * 添加定时任务
     * @param jobName 任务名称
     * @param jobClazz 任务job
     * @param cron 执行时间之cron表达式
     * @param params 任务job参数
     */
    public void addJob(String jobName , Class jobClazz , String cron, HashMap<String,String> params){
        try {
            //获取Scheduler
            Scheduler scheduler = getScheduled();
            // 任务名,任务组,任务执行类
            JobDetail jobDetail= JobBuilder.newJob(jobClazz).withIdentity(jobName, JOB_GROUP_NAME).build();
            // 传参(可选)
            JobDataMap jobDataMap = jobDetail.getJobDataMap();
            if(params != null ){
                for (String key:params.keySet()){
                    jobDataMap.put(key, params.get(key));
                }
            }
            // 触发器
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            // 触发器名,触发器组
            triggerBuilder.withIdentity(jobName, TRIGGER_GROUP_NAME);
            triggerBuilder.startNow();
            // 触发器时间设定
            triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
            // 创建Trigger对象
            CronTrigger trigger = (CronTrigger) triggerBuilder.build();
            // 调度容器设置JobDetail和Trigger
            scheduler.scheduleJob(jobDetail, trigger);
            // 启动
            if (!scheduler.isShutdown()) {
                scheduler.start();
            }
            quartzInfoRepository.save(new ScheduleInfo(jobName,JOB_GROUP_NAME,
                                                       jobName,TRIGGER_GROUP_NAME,0));
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除定时任务
     * @param jobName 任务名称
     */
    public void removeJob(String jobName) {
        try {
            Scheduler scheduler = getScheduled();
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME);
            scheduler.pauseTrigger(triggerKey);// 停止触发器
            scheduler.unscheduleJob(triggerKey);// 移除触发器
            scheduler.deleteJob(JobKey.jobKey(jobName, JOB_GROUP_NAME));// 删除任务
            System.out.println("删除定时任务"+jobName);
            ScheduleInfo quartzInfo = quartzInfoRepository.findByJobDetailName(jobName);
            if(quartzInfo != null){
                quartzInfoRepository.deleteById(quartzInfo.getId());
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除定时任务
     * @param jobName 任务名称
     */
    public void removeDefaultJob(String jobName) {
        try {
            Scheduler scheduler = getScheduled();
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, DEFAULT_GROUP_NAME);
            scheduler.pauseTrigger(triggerKey);// 停止触发器
            scheduler.unscheduleJob(triggerKey);// 移除触发器
            scheduler.deleteJob(JobKey.jobKey(jobName, DEFAULT_GROUP_NAME));// 删除任务
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 启动任务
     */
    public void startJobs() {
        try {
            Scheduler scheduler = getScheduled();
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭任务
     */
    public void shutdownJobs() {
        try {
            Scheduler scheduler = getScheduled();
            if (!scheduler.isShutdown()) {
                scheduler.shutdown();
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取所有任务
     */
    public List<String> getAllJob(){
        List<String> jobs = new ArrayList<>();
        try {
            Set<JobKey> jobKeys = getScheduled().getJobKeys(GroupMatcher.anyGroup());
            for(JobKey jobKey:jobKeys){
                jobs.add(jobKey.getName());
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return jobs;
    }
}

4.5、定义Job

import com.example.quartzdemo.dao.QuartzInfoRepository;
import com.example.quartzdemo.model.ScheduleInfo;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

/**
 * 通过web页面创建的定时任务job
 * @author tom
 * @version V1.0
 * @date 2020/10/4 15:30
 */
@Component
public class WebJob implements Job {

    @Autowired
    QuartzInfoRepository quartzInfoRepository;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap dataMap = context.getMergedJobDataMap();
        HashMap<String,String> map = new HashMap<>();
        for(Object o:dataMap.keySet()){
            map.put((String)o,dataMap.getString((String)o));
        }

        String jobName = context.getJobDetail().getKey().getName();
        ScheduleInfo quartzInfo = quartzInfoRepository.findByJobDetailName(jobName);
        if(quartzInfo != null){
            quartzInfo.setExecuteCount(quartzInfo.getExecuteCount()+1);
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String nowDate = df.format(new Date());
            System.out.println(nowDate+ " my web job prams: "+map.toString()+quartzInfo.getExecuteCount());
            quartzInfoRepository.save(quartzInfo);
        }
    }
}

4.6、controller接口类

import com.example.quartzdemo.job.WebJob;
import com.example.quartzdemo.model.Response;
import com.example.quartzdemo.quartzManager.QuartzManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;

/**
 * 定时任务的增删查
 *
 * @author tom
 * @version V1.0
 * @date 2020/10/4 14:50
 */
@RestController
@RequestMapping("/quartz")
public class QuartzController {

    @Autowired
    QuartzManager quartzManager;

    /**
     * 添加定时任务
     *
     * @param jobName
     * @return
     */
    @GetMapping("/addJob")
    public Response addJob(String jobName) {
        String cron = "0/3 * * * * ?";
        HashMap<String, String> map = new HashMap<>();
        map.put("jobName", jobName);
        quartzManager.addJob(jobName, WebJob.class, cron, map);
        return new Response("job添加成功", "");
    }

    /**
     * 删除定时任务
     *
     * @param jobName
     * @return
     */
    @GetMapping("/deleteJob")
    public Response deleteJob(String jobName) {
        quartzManager.removeJob(jobName);
        return new Response("job删除成功", "");
    }

    /**
     * 删除默认定时任务
     *
     * @param jobName
     * @return
     */
    @GetMapping("/removeDefaultJob")
    public Response removeDefaultJob(String jobName) {
        quartzManager.removeDefaultJob(jobName);
        return new Response("job删除成功", "");
    }

    /**
     * 查询所有定时任务
     *
     * @param jobName
     * @return
     */
    @GetMapping("/getAllJob")
    public Response getAllJob(String jobName) {
        return new Response("成功获取所有job", quartzManager.getAllJob());
    }

}

5、启动项目看看效果

复制2个项目出来,三个项目分别改一下端口为8081、8082、8083,依次启动项目
在这里插入图片描述
我们查一下所有定时任务发现为空
http://localhost:8081/quartz/getAllJob
在这里插入图片描述
添加一个定时任务
http://localhost:8081/quartz/addJob?jobName=JsonTom888
我们发现定时任务正常运行,输出如下结果,这个时候另外两个服务并没有任何输出,这个时候我们并不能确定定时任务集群状态满足了我们的要求。
在这里插入图片描述
继续添加一个定时任务
http://localhost:8081/quartz/addJob?jobName=Json888
我们发现定时任务正常启动,通过数字我们能够确认每次任务只在一个实例上运行了一次,但是运气不佳,还是只在同一个实例上运行
在这里插入图片描述
我们尝试删除一个定时任务看看
http://localhost:8081/quartz/addJob?jobName=Json888
这时我们发现同时在三个实例上输出了如下内容,说明quartz自动进行了负载均衡策略,通过每一行的时间和后面的数字,我们发现同一定时任务同一时间只在一个实例上运行了一次,符合我们集群状态下的预想。
在这里插入图片描述
总结:我们可以添加更多的定时任务看看效果,每次结果在每个实例上输出的可能不一样,但是我们能看出同一定时任务同一时间只在一个实例上运行一次,符合我们集群状态下的预想。

项目代码地址
https://github.com/JsonTom888/scheduledAndQuartz/tree/master/quartzcluster

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中,可以通过集成Quartz框架来实现动态创建定时任务。下面是一个简单的示例,演示如何查询数据库来创建定时任务。 首先,需要在pom.xml文件中添加Quartz和MySQL的依赖: ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies> ``` 然后,需要在application.properties文件中配置数据库连接信息: ```properties spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.jdbc.Driver ``` 接下来,可以定义一个ScheduledJob实体类,用于映射数据库中的定时任务数据: ```java @Entity @Table(name = "scheduled_job") public class ScheduledJob { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String group; private String cronExpression; private String description; // getters and setters } ``` 然后,创建一个JobFactory类,继承SpringBeanJobFactory,并重写createJobInstance方法,用于将Job实例交给Spring容器进行管理: ```java public class JobFactory extends SpringBeanJobFactory implements ApplicationContextAware { private transient AutowireCapableBeanFactory beanFactory; @Override public void setApplicationContext(final ApplicationContext context) { beanFactory = context.getAutowireCapableBeanFactory(); } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); return job; } } ``` 最后,创建一个JobScheduler类,用于从数据库中读取定时任务数据,并创建对应的定时任务: ```java @Component public class JobScheduler { @Autowired private SchedulerFactory schedulerFactory; @Autowired private JobFactory jobFactory; @Autowired private DataSource dataSource; @PostConstruct public void init() throws Exception { final Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.setJobFactory(jobFactory); final String sql = "select * from scheduled_job"; try (final Connection connection = dataSource.getConnection(); final PreparedStatement statement = connection.prepareStatement(sql); final ResultSet resultSet = statement.executeQuery()) { while (resultSet.next()) { final JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class) .withIdentity(resultSet.getString("name"), resultSet.getString("group")) .withDescription(resultSet.getString("description")) .build(); final Trigger trigger = TriggerBuilder.newTrigger() .withIdentity(resultSet.getString("name"), resultSet.getString("group")) .withSchedule(CronScheduleBuilder.cronSchedule(resultSet.getString("cron_expression"))) .build(); scheduler.scheduleJob(jobDetail, trigger); } scheduler.start(); } } } ``` 在上面的代码中,首先通过SchedulerFactory获取Scheduler实例,并设置JobFactory。然后,通过数据库查询语句从数据库中获取定时任务数据,并创建对应的JobDetail和Trigger实例。最后,将JobDetail和Trigger实例添加到Scheduler中,并启动Scheduler。 需要注意的是,QuartzJob类需要继承QuartzJobBean,并实现executeInternal方法,用于执行定时任务的具体逻辑: ```java public class QuartzJob extends QuartzJobBean { @Override protected void executeInternal(final JobExecutionContext context) throws JobExecutionException { // 定时任务逻辑 } } ``` 至此,一个动态创建定时任务的示例就完成了。需要注意的是,该示例仅供参考,实际应用中还需要考虑很多细节问题,如异常处理、任务状态管理等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值