springBoot

发布时间:2025-03-09 04:54

1.1 Quartz 概述

Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目,完全基于 Java 实现。该项目于 2009 年被 Terracotta 收购,目前是 Terracotta 旗下的一个项目。读者可以到 http://www.quartz-scheduler.org/站点下载 Quartz 的发布版本及其源代码。

1.2 Quartz特点

作为一个优秀的开源调度框架,Quartz 具有以下特点:

强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求;
灵活的应用方式,例如支持任务和调度的多种组合方式,支持调度数据的多种存储方式;
分布式和集群能力,Terracotta 收购后在原来功能基础上作了进一步提升。
另外,作为 Spring 默认的调度框架,Quartz 很容易与 Spring 集成实现灵活可配置的调度功能。

quartz调度核心元素: Scheduler:任务调度器,是实际执行任务调度的控制器。在spring中通过SchedulerFactoryBean封装起来。Trigger:触发器,用于定义任务调度的时间规则,有SimpleTrigger,CronTrigger,DateIntervalTrigger和NthIncludedDayTrigger,其中CronTrigger用的比较多,本文主要介绍这种方式。CronTrigger在spring中封装在CronTriggerFactoryBean中。Calendar:它是一些日历特定时间点的集合。一个trigger可以包含多个Calendar,以便排除或包含某些时间点。JobDetail:用来描述Job实现类及其它相关的静态信息,如Job名字、关联监听器等信息。在spring中有JobDetailFactoryBean和 MethodInvokingJobDetailFactoryBean两种实现,如果任务调度只需要执行某个类的某个方法,就可以通过MethodInvokingJobDetailFactoryBean来调用。Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中。实现Job接口的任务,默认是无状态的,若要将Job设置成有状态的,在quartz中是给实现的Job添加@DisallowConcurrentExecution注解(以前是实现StatefulJob接口,现在已被Deprecated),在与spring结合中可以在spring配置文件的job detail中配置concurrent参数。

1.3 Quartz 集群配置

quartz集群是通过数据库表来感知其他的应用的,各个节点之间并没有直接的通信。只有使用持久的JobStore才能完成Quartz集群。
数据库表:以前有12张表,现在只有11张表,现在没有存储listener相关的表,多了QRTZ_SIMPROP_TRIGGERS表:

建表sql 点这里
如果没有积分可以留言,我发给你哦。只是可能会比较晚
在这里插入图片描述
QRTZ_LOCKS就是Quartz集群实现同步机制的行锁表,包括以下几个锁:CALENDAR_ACCESS 、JOB_ACCESS、MISFIRE_ACCESS 、STATE_ACCESS 、TRIGGER_ACCESS。

动手

记得要先新建数据库,新建默认创建的11 张表哦

导入maven 依赖

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--quartz--> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency> <!--因为quartz 需要有Spring context 所有引入mail包--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency>

12345678910111213141516171819202122232425262728293031323334353637 QuartzConfig

package com.abel.quartz.config; import java.beans.PropertyVetoException; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Properties; import com.zaxxer.hikari.HikariDataSource; import org.quartz.Job; import org.quartz.JobDetail; import org.quartz.Trigger; 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.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.JobDetailFactoryBean; import org.springframework.scheduling.quartz.SchedulerFactoryBean; /** * Created by yangyibo on 2019/1/16. */ @Configuration public class QuartzConfig { /** * 1.通过name+group获取唯一的jobKey;2.通过groupname来获取其下的所有jobkey */ final static String GROUP_NAME = "QuartzJobGroups"; @Value("${quartz.scheduler.instanceName}") private String quartzInstanceName; @Value("${spring.datasource.driverClassName}") private String myDSDriver; @Value("${spring.datasource.url}") private String myDSUrl; @Value("${spring.datasource.username}") private String myDSUser; @Value("${spring.datasource.password}") private String myDSPassword; @Value("${org.quartz.dataSource.myDS.maxConnections}") private int myDSMaxConnections; /** * 设置属性 * * @return * @throws IOException */ private Properties quartzProperties() throws IOException { Properties prop = new Properties(); // 调度标识名 集群中每一个实例都必须使用相同的名称 prop.put("quartz.scheduler.instanceName", quartzInstanceName); // ID设置为自动获取 每一个必须不同 prop.put("org.quartz.scheduler.instanceId", "AUTO"); // 禁用quartz软件更新 prop.put("org.quartz.scheduler.skipUpdateCheck", "true"); prop.put("org.quartz.scheduler.jmx.export", "true"); // 数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库 prop.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate"); // 数据保存方式为数据库持久化 prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX"); // 数据库别名 随便取 prop.put("org.quartz.jobStore.dataSource", "quartzDataSource"); //prop.put("org.quartz.jobStore.dataSource", "myDS"); // 表的前缀,默认QRTZ_ prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); // 是否加入集群 prop.put("org.quartz.jobStore.isClustered", "true"); // 调度实例失效的检查时间间隔 prop.put("org.quartz.jobStore.clusterCheckinInterval", "20000"); prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1"); // 信息保存时间 ms 默认值60秒 prop.put("org.quartz.jobStore.misfireThreshold", "120000"); prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true"); prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE"); // 程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求) prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); // 定线程数,至少为1(无默认值)(一般设置为1-100之间的整数合适) prop.put("org.quartz.threadPool.threadCount", "10"); // 设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5) prop.put("org.quartz.threadPool.threadPriority", "5"); prop.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", "true"); prop.put("org.quartz.plugin.triggHistory.class", "org.quartz.plugins.history.LoggingJobHistoryPlugin"); prop.put("org.quartz.plugin.shutdownhook.class", "org.quartz.plugins.management.ShutdownHookPlugin"); prop.put("org.quartz.plugin.shutdownhook.cleanShutdown", "true"); //#自定义连接池 //org.quartz.dataSource.myDS.connectionProvider.class=com.poly.pay.schedule.DruidConnectionProvider return prop; } /** * 数据源 * * @return * @throws PropertyVetoException */ @Bean public HikariDataSource createDataSource() throws PropertyVetoException { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(myDSUrl); dataSource.setDriverClassName(myDSDriver); dataSource.setUsername(myDSUser); dataSource.setPassword(myDSPassword); dataSource.setMaximumPoolSize(myDSMaxConnections); return dataSource; } /** * 创建触发器工厂 * * @param jobDetail * @param cronExpression * @return */ private static CronTriggerFactoryBean cronTriggerFactoryBean(JobDetail jobDetail, String cronExpression) { CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean(); factoryBean.setJobDetail(jobDetail); factoryBean.setCronExpression(cronExpression); return factoryBean; } /****************************************************以下配置需要注意******************************************************/ /** * 调度工厂 * 此处配置需要调度的触发器 例如 executeJobTrigger * * @param executeJobTrigger * @return * @throws IOException * @throws PropertyVetoException */ @Bean public SchedulerFactoryBean schedulerFactoryBean(@Qualifier("executeJobTrigger") Trigger executeJobTrigger) throws IOException, PropertyVetoException { SchedulerFactoryBean factory = new SchedulerFactoryBean(); // this allows to update triggers in DB when updating settings in config file: //用于quartz集群,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 factory.setOverwriteExistingJobs(true); //用于quartz集群,加载quartz数据源 //factory.setDataSource(dataSource); //QuartzScheduler 延时启动,应用启动完10秒后 QuartzScheduler 再启动 //factory.setStartupDelay(10); //用于quartz集群,加载quartz数据源配置 factory.setAutoStartup(true); factory.setQuartzProperties(quartzProperties()); factory.setApplicationContextSchedulerContextKey("applicationContext"); factory.setDataSource(createDataSource()); //注册触发器 Trigger[] triggers = {executeJobTrigger}; factory.setTriggers(triggers); return factory; } /** * 加载触发器 * * 新建触发器进行job 的调度 例如 executeJobDetail * @param jobDetail * @return */ @Bean(name = "executeJobTrigger") public CronTriggerFactoryBean executeJobTrigger(@Qualifier("executeJobDetail") JobDetail jobDetail) { //每天凌晨3点执行 return cronTriggerFactoryBean(jobDetail, "0 1 0 * * ? "); } /** * 加载job * * 新建job 类用来代理 * * * @return */ @Bean public JobDetailFactoryBean executeJobDetail() { return createJobDetail(InvokingJobDetailFactory.class, GROUP_NAME, "executeJob"); } /** * 执行规则job工厂 * * 配置job 类中需要定时执行的 方法 execute * @param jobClass * @param groupName * @param targetObject * @return */ private static JobDetailFactoryBean createJobDetail(Class<? extends Job> jobClass, String groupName, String targetObject) { JobDetailFactoryBean factoryBean = new JobDetailFactoryBean(); factoryBean.setJobClass(jobClass); factoryBean.setDurability(true); factoryBean.setRequestsRecovery(true); factoryBean.setGroup(groupName); Map<String, String> map = new HashMap<>(); map.put("targetMethod", "execute"); map.put("targetObject", targetObject); factoryBean.setJobDataAsMap(map); return factoryBean; } }

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 InvokingJobDetailFactory

package com.abel.quartz.config; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.context.ApplicationContext; import org.springframework.scheduling.quartz.QuartzJobBean; import java.lang.reflect.Method; /** * Created by yangyibo on 2019/2/1. */ public class InvokingJobDetailFactory extends QuartzJobBean { /** * 计划任务所在类 */ private String targetObject; /** * 具体需要执行的计划任务 */ private String targetMethod; private ApplicationContext ctx; @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { try { Object obj = ctx.getBean(targetObject); Method m = null; try { m = obj.getClass().getMethod(targetMethod); //调用被代理对象的方法 m.invoke(obj); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } catch (Exception e) { throw new JobExecutionException(e); } } public void setApplicationContext(ApplicationContext applicationContext) { this.ctx = applicationContext; } public void setTargetObject(String targetObject) { this.targetObject = targetObject; } public void setTargetMethod(String targetMethod) { this.targetMethod = targetMethod; } }

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 ExecuteJob

package com.abel.quartz.job; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; /** * Created by yangyibo on 2019/2/1. */ @Service public class ExecuteJob { private static final Logger logger = LoggerFactory.getLogger(ExecuteJob.class); /** * 方法名在quartz定义 */ public void execute() { System.out.println("定时任务执行了。。。。。"); } }

12345678910111213141516171819202122

application.properties

## tomcat配置 server.port=8090 #server.tomcat.maxHttpHeaderSize=8192 server.tomcat.uri-encoding=UTF-8 spring.http.encoding.charset=UTF-8 spring.http.encoding.enabled=true spring.http.encoding.force=true spring.messages.encoding=UTF-8 # tomcat最大线程数,默认为200 server.tomcat.max-threads=800 # session最大超时时间(分钟),默认为30 server.session-timeout=60 ## spring 配置 spring.application.name=springboot-Quartz application.main=com.abel.quartz.Application ## 主数据源,默认的 spring.datasource.url=jdbc:mysql://localhost:3306/quart?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.username=root spring.datasource.password=admin spring.datasource.driverClassName=com.mysql.jdbc.Driver ## 连接池配置 spring.datasource.type=com.zaxxer.hikari.HikariDataSource #最小空闲连接 spring.datasource.hikari.minimum-idle=10 #连接池中允许的最大连接数。缺省值:10;推荐的公式:((core_count * 2) + effective_spindle_count) spring.datasource.hikari.maximum-pool-size=30 #spring.datasource.hikari.auto-commit=true #一个连接idle状态的最大时长(毫秒),超时则被释放(retired),缺省:10分钟。minimumIdle<maximumPoolSize时生效 spring.datasource.hikari.idle-timeout=120000 #自定义连接池名 #spring.datasource.hikari.pool-name=DatebookHikariCP #一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),缺省:30分钟,建议设置比数据库超时时长少30秒,参考MySQL wait_timeout参数(show variables like '%timeout%';) spring.datasource.hikari.max-lifetime=1800000 #等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒 spring.datasource.hikari.connection-timeout=30000 #指定验证连接有效性的超时时间,默认是5秒 spring.datasource.hikari.validation-timeout=3000 spring.datasource.hikari.connection-test-query=SELECT 1 # 调度标识名 集群中每一个实例都必须使用相同的名称 quartz.scheduler.instanceName=QuartScheduler # 允许最大连接 org.quartz.dataSource.myDS.maxConnections=10

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647

源代码地址:https://github.com/527515025/springBoot/tree/master/springboot-Quartz
参考资料:https://blog.csdn.net/lkl_csdn/article/details/73613033

网址:springBoot https://www.yuejiaxmz.com/news/view/815020

相关内容

Springboot基于SpringBoot的宠物门诊系统6f8jy
二手家电交易系统(SpringBoot,SSM,MySQL)
java springboot校园二手书籍交易的设计与实现
springboot中unexpected error (type=Not Found, status=404)/WEB
Springboot/java/node/python/php教务管理系统【2024年毕设】
【附源码】springboot 大学生家教管理系统设计与实现
【附源码】springboot 自驾游攻略查询系统设计与实现
【附源码】springboot 轻院网购商城管理系统设计与实现
基于SpringBoot+Vue的家政预约平台系统
基于springboot的疫情社区生活服务系统

随便看看