SSM 整合 quartz JDBC方式实现job动态增删改查记录
虽然网上有很多资料,但是都不够系统,本文记录下自己的整合过程.
1. 搭建一个SSM项目,此处略.
2. 按照quartz官方要求,建立quartz相关的数据库和表,相关sql语句如下:
/* Navicat MySQL Data Transfer Source Server : local_mysql Source Server Version : 50537 Source Host : localhost:3306 Source Database : quartz_test Target Server Type : MYSQL Target Server Version : 50537 File Encoding : 65001 Date: 2017-03-07 15:11:44 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for qrtz_blob_triggers -- ---------------------------- create database quartz_test; DROP TABLE IF EXISTS `qrtz_blob_triggers`; CREATE TABLE `qrtz_blob_triggers` ( `sched_name` varchar(120) NOT NULL, `trigger_name` varchar(80) NOT NULL, `trigger_group` varchar(80) NOT NULL, `blob_data` blob, PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`), CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of qrtz_blob_triggers -- ---------------------------- -- ---------------------------- -- Table structure for qrtz_calendars -- ---------------------------- DROP TABLE IF EXISTS `qrtz_calendars`; CREATE TABLE `qrtz_calendars` ( `sched_name` varchar(120) NOT NULL, `calendar_name` varchar(80) NOT NULL, `calendar` blob NOT NULL, PRIMARY KEY (`calendar_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of qrtz_calendars -- ---------------------------- -- ---------------------------- -- Table structure for qrtz_cron_triggers -- ---------------------------- DROP TABLE IF EXISTS `qrtz_cron_triggers`; CREATE TABLE `qrtz_cron_triggers` ( `sched_name` varchar(120) NOT NULL, `trigger_name` varchar(80) NOT NULL, `trigger_group` varchar(80) NOT NULL, `cron_expression` varchar(120) NOT NULL, `time_zone_id` varchar(80) DEFAULT NULL, PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`), CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of qrtz_cron_triggers -- ---------------------------- -- ---------------------------- -- Table structure for qrtz_fired_triggers -- ---------------------------- DROP TABLE IF EXISTS `qrtz_fired_triggers`; CREATE TABLE `qrtz_fired_triggers` ( `sched_name` varchar(120) NOT NULL, `entry_id` varchar(95) NOT NULL, `trigger_name` varchar(80) NOT NULL, `trigger_group` varchar(80) NOT NULL, `instance_name` varchar(80) NOT NULL, `fired_time` bigint(20) NOT NULL, `sched_time` bigint(20) NOT NULL, `priority` int(11) NOT NULL, `state` varchar(16) NOT NULL, `job_name` varchar(80) DEFAULT NULL, `job_group` varchar(80) DEFAULT NULL, `is_nonconcurrent` int(11) DEFAULT NULL, `requests_recovery` int(11) DEFAULT NULL, PRIMARY KEY (`sched_name`,`entry_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of qrtz_fired_triggers -- ---------------------------- INSERT INTO `qrtz_fired_triggers` VALUES ('dufy_test', 'NON_CLUSTERED1487230171387', 'trigger1', 'group1', 'NON_CLUSTERED', '1487230212028', '1487230214000', '5', 'ACQUIRED', null, null, '0', '0'); -- ---------------------------- -- Table structure for qrtz_job_details -- ---------------------------- DROP TABLE IF EXISTS `qrtz_job_details`; CREATE TABLE `qrtz_job_details` ( `sched_name` varchar(120) NOT NULL, `job_name` varchar(80) NOT NULL, `job_group` varchar(80) NOT NULL, `description` varchar(120) DEFAULT NULL, `job_class_name` varchar(128) NOT NULL, `is_durable` int(11) NOT NULL, `is_nonconcurrent` int(11) NOT NULL, `is_update_data` int(11) NOT NULL, `requests_recovery` int(11) NOT NULL, `job_data` blob, PRIMARY KEY (`sched_name`,`job_name`,`job_group`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of qrtz_job_details -- ---------------------------- -- ---------------------------- -- Table structure for qrtz_locks -- ---------------------------- DROP TABLE IF EXISTS `qrtz_locks`; CREATE TABLE `qrtz_locks` ( `sched_name` varchar(120) NOT NULL, `lock_name` varchar(40) NOT NULL, PRIMARY KEY (`sched_name`,`lock_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of qrtz_locks -- ---------------------------- INSERT INTO `qrtz_locks` VALUES ('dufy_test', 'TRIGGER_ACCESS'); INSERT INTO `qrtz_locks` VALUES ('quartzScheduler', 'TRIGGER_ACCESS'); INSERT INTO `qrtz_locks` VALUES ('scheduler', 'TRIGGER_ACCESS'); -- ---------------------------- -- Table structure for qrtz_paused_trigger_grps -- ---------------------------- DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`; CREATE TABLE `qrtz_paused_trigger_grps` ( `sched_name` varchar(120) NOT NULL, `trigger_group` varchar(80) NOT NULL, PRIMARY KEY (`sched_name`,`trigger_group`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of qrtz_paused_trigger_grps -- ---------------------------- -- ---------------------------- -- Table structure for qrtz_scheduler_state -- ---------------------------- DROP TABLE IF EXISTS `qrtz_scheduler_state`; CREATE TABLE `qrtz_scheduler_state` ( `sched_name` varchar(120) NOT NULL, `instance_name` varchar(80) NOT NULL, `last_checkin_time` bigint(20) NOT NULL, `checkin_interval` bigint(20) NOT NULL, PRIMARY KEY (`sched_name`,`instance_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of qrtz_scheduler_state -- ---------------------------- -- ---------------------------- -- Table structure for qrtz_simple_triggers -- ---------------------------- DROP TABLE IF EXISTS `qrtz_simple_triggers`; CREATE TABLE `qrtz_simple_triggers` ( `sched_name` varchar(120) NOT NULL, `trigger_name` varchar(80) NOT NULL, `trigger_group` varchar(80) NOT NULL, `repeat_count` bigint(20) NOT NULL, `repeat_interval` bigint(20) NOT NULL, `times_triggered` bigint(20) NOT NULL, PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`), CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of qrtz_simple_triggers -- ---------------------------- -- ---------------------------- -- Table structure for qrtz_simprop_triggers -- ---------------------------- DROP TABLE IF EXISTS `qrtz_simprop_triggers`; CREATE TABLE `qrtz_simprop_triggers` ( `sched_name` varchar(120) NOT NULL, `TRIGGER_NAME` varchar(200) NOT NULL, `TRIGGER_GROUP` varchar(200) NOT NULL, `STR_PROP_1` varchar(512) DEFAULT NULL, `STR_PROP_2` varchar(512) DEFAULT NULL, `STR_PROP_3` varchar(512) DEFAULT NULL, `INT_PROP_1` int(11) DEFAULT NULL, `INT_PROP_2` int(11) DEFAULT NULL, `LONG_PROP_1` bigint(20) DEFAULT NULL, `LONG_PROP_2` bigint(20) DEFAULT NULL, `DEC_PROP_1` decimal(13,4) DEFAULT NULL, `DEC_PROP_2` decimal(13,4) DEFAULT NULL, `BOOL_PROP_1` varchar(1) DEFAULT NULL, `BOOL_PROP_2` varchar(1) DEFAULT NULL, PRIMARY KEY (`sched_name`,`TRIGGER_NAME`,`TRIGGER_GROUP`), CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of qrtz_simprop_triggers -- ---------------------------- -- ---------------------------- -- Table structure for qrtz_triggers -- ---------------------------- DROP TABLE IF EXISTS `qrtz_triggers`; CREATE TABLE `qrtz_triggers` ( `sched_name` varchar(120) NOT NULL, `trigger_name` varchar(80) NOT NULL, `trigger_group` varchar(80) NOT NULL, `job_name` varchar(80) NOT NULL, `job_group` varchar(80) NOT NULL, `description` varchar(120) DEFAULT NULL, `next_fire_time` bigint(20) DEFAULT NULL, `prev_fire_time` bigint(20) DEFAULT NULL, `priority` int(11) DEFAULT NULL, `trigger_state` varchar(16) NOT NULL, `trigger_type` varchar(8) NOT NULL, `start_time` bigint(20) NOT NULL, `end_time` bigint(20) DEFAULT NULL, `calendar_name` varchar(80) DEFAULT NULL, `misfire_instr` smallint(6) DEFAULT NULL, `job_data` blob, PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`), KEY `sched_name` (`sched_name`,`job_name`,`job_group`), CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `job_name`, `job_group`) REFERENCES `qrtz_job_details` (`sched_name`, `job_name`, `job_group`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of qrtz_triggers -- ---------------------------- -- ---------------------------- -- Table structure for user_t -- ---------------------------- DROP TABLE IF EXISTS `user_t`; CREATE TABLE `user_t` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_name` varchar(40) NOT NULL, `password` varchar(255) NOT NULL, `age` int(4) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user_t -- ---------------------------- INSERT INTO `user_t` VALUES ('1', 'admin', '123456', '24');
3. 在resources目录下放入 quartz.properties 文件
相关内容:
# Default Properties file for use by StdSchedulerFactory # to create a Quartz Scheduler Instance, if a different # properties file is not explicitly specified. # #============================================================================ # Configure Main Scheduler Properties #============================================================================ org.quartz.scheduler.instanceName: quartzScheduler org.quartz.scheduler.instanceId = AUTO org.quartz.scheduler.rmi.export: false org.quartz.scheduler.rmi.proxy: false org.quartz.scheduler.wrapJobExecutionInUserTransaction: false #============================================================================ # Configure ThreadPool #============================================================================ org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount: 2 org.quartz.threadPool.threadPriority: 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true org.quartz.jobStore.misfireThreshold: 60000 #============================================================================ # Configure JobStore #============================================================================ #default config #org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore #\u6301\u4e45\u5316\u914d\u7f6e org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX #org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate #org.quartz.jobStore.useProperties:true #============================================================================ #havent cluster spring #============================================================================ org.quartz.jobStore.isClustered = false #\u6570\u636e\u5e93\u8868\u524d\u7f00 #org.quartz.jobStore.tablePrefix:qrtz_ org.quartz.jobStore.dataSource:qzDS #============================================================================ # Configure Datasources #============================================================================ #JDBC\u9a71\u52a8 Sping\u53bb\u7ba1\u7406dataSource \uff0c\u8fd9\u91cc\u4e0d\u5728\u914d\u7f6e\u6570\u636e\u6e90\u4fe1\u606f org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver #下面的数据库配置换成自己的 org.quartz.dataSource.qzDS.URL:jdbc:mysql://xx.xx.xx.xx:3306/quartz_test org.quartz.dataSource.qzDS.user:root org.quartz.dataSource.qzDS.password:123456 #该配置启用会报错 #org.quartz.dataSource.qzDS.maxConnection:10
3. 自定义jobfactory---此处主要是为了让Job实例能够被纳入spring容器,从而使用诸如@Service @Repository之类的spring组件
@Component("customJobFactory") public class CustomJobFactory extends SpringBeanJobFactory { @Autowired private AutowireCapableBeanFactory beanFactory; @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { Object instance = super.createJobInstance(bundle); beanFactory.autowireBean(instance); return instance; } }
4. spring-quartz.xml 此配置文件主要是提供一个scheduler对象供容器里的bean引用
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >
<!-- 此处要配置可用datasource--> <property name="dataSource" ref ="dataSource" /> <property name="applicationContextSchedulerContextKey" value="applicationContextKey"/> <property name="configLocation" value="classpath:quartz.properties"/> <!--可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 --> <property name="overwriteExistingJobs" value="true" /> <!--必须的,QuartzScheduler 延时启动,应用启动完后 QuartzScheduler 再启动 --> <property name="startupDelay" value="10" /> <!-- 设置自动启动 <property name="autoStartup" value="true" /> -->
<!-- 配置自定义的jobfactory -->
<property name="jobFactory" ref="customJobFactory"/>
</bean>
</beans>
5. spring-mybatis.xml 此文件引入spring-quartz.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 扫描有@component @service的类包并将其归入bean内 --> <context:component-scan base-package="com.jd.ptest.urlmonitor"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" p:driverClassName="${jdbc.driver}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}"> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:mybatis/mapping/*"/> <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/> </bean> <!-- 扫描直接使用mapper接口类操作dao --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.xx.xx.xx.dao"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean> <!-- 使用提供的template --> <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg ref="sqlSessionFactory"></constructor-arg> </bean> <!-- 配置事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置基于注解的声明式事务--> <tx:annotation-driven transaction-manager="transactionManager"/> <!-- 加载计划任务类 --> <import resource="spring-quartz.xml"/> <!-- 加载spring中的资源文件 必须放在最后! --> <import resource="spring-profiles.xml"/> </beans>
6. job类 用于干活的类
public class ScheduleRegionJob { Log log = LogFactory.getLog(this.getClass()); @Value("${baseUrl}") private String baseUrl; @Value("${token}") private String token; @Value("${pageSize}") private String pageSize; @Value("${region}") private String region; //此处可以引用spring容器的bean @Autowired @SuppressWarnings("all") private IRegionService regionService; @Autowired @SuppressWarnings("all") private IMailService mailService; /** * 定时同步机房信息的方法 */ public void sheduledSyncJob() { try { log.info("开始启动计划任务sheduledSyncJob!" ); regionService.syncRegionByUrl(baseUrl, token,Integer.parseInt(pageSize)); } catch (Exception e) { e.printStackTrace(); } } public void sheduledMonitorJob(){ boolean isSuc =false; try { String summaryId = regionService.doRegionMonitor(region); //发送报警邮件 mailService.productMail(summaryId); isSuc = true; } catch (Exception e) { isSuc = false; e.printStackTrace(); }finally { if(isSuc){ log.error( "Region monitor successful!"); }else{ log.error("Region monitor failed!"); } } } }
7. QuartzServiceImpl quartz job 操作类
@Service("quartzService") public class QuartzServiceImpl implements IQuartzService { @Autowired @SuppressWarnings("all") private Scheduler quartzScheduler; @Override public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Class cls, String cron) { try { // 获取调度器 Scheduler sched = quartzScheduler; // 创建一项作业 JobDetail job = JobBuilder.newJob(cls) .withIdentity(jobName, jobGroupName).build(); // 创建一个触发器 CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(triggerName, triggerGroupName) .withSchedule(CronScheduleBuilder.cronSchedule(cron)) .build(); // 告诉调度器使用该触发器来安排作业 sched.scheduleJob(job, trigger); // 启动 if (!sched.isShutdown()) { sched.start(); } } catch (Exception e) { throw new RuntimeException(e); } } /** * 修改定时器任务信息 */ @Override public boolean modifyJob(String oldjobName, String oldjobGroup, String oldtriggerName, String oldtriggerGroup, String jobName, String jobGroup, String triggerName, String triggerGroup, String cron) { try { Scheduler sched = quartzScheduler; CronTrigger trigger = (CronTrigger) sched.getTrigger(TriggerKey .triggerKey(oldtriggerName, oldtriggerGroup)); if (trigger == null) { return false; } JobKey jobKey = JobKey.jobKey(oldjobName, oldjobGroup); TriggerKey triggerKey = TriggerKey.triggerKey(oldtriggerName, oldtriggerGroup); JobDetail job = sched.getJobDetail(jobKey); Class jobClass = job.getJobClass(); // 停止触发器 sched.pauseTrigger(triggerKey); // 移除触发器 sched.unscheduleJob(triggerKey); // 删除任务 sched.deleteJob(jobKey); addJob(jobName, jobGroup, triggerName, triggerGroup, jobClass, cron); return true; } catch (Exception e) { throw new RuntimeException(e); } } @Override public boolean modifyJobCron(String triggerName, String triggerGroupName, String cronExpression) throws Exception { boolean flag = false; try { Scheduler sched = quartzScheduler; TriggerKey triggerKey = TriggerKey.triggerKey(triggerName,triggerGroupName); CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey); if (trigger == null) { flag = false; } String oldExpression = trigger.getCronExpression(); if (!oldExpression.equalsIgnoreCase(cronExpression)) { TriggerBuilder builder = TriggerBuilder .newTrigger() .withIdentity(triggerName,triggerGroupName); CronTrigger newTrigger = (CronTrigger)builder .startNow() .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) .build(); // 重启触发器 sched.rescheduleJob(triggerKey,newTrigger); flag = true; } } catch (Exception e) { flag = false; throw e; }finally { return flag; } } @Override public void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) { try { Scheduler sched = quartzScheduler; // 停止触发器 sched.pauseTrigger(TriggerKey.triggerKey(triggerName, triggerGroupName)); // 移除触发器 sched.unscheduleJob(TriggerKey.triggerKey(triggerName, triggerGroupName)); // 删除任务 sched.deleteJob(JobKey.jobKey(jobName, jobGroupName)); } catch (Exception e) { throw new RuntimeException(e); } } @Override public void startSchedule() { try { Scheduler sched = quartzScheduler; sched.start(); } catch (Exception e) { throw new RuntimeException(e); } } @Override public void shutdownSchedule() { try { Scheduler sched = quartzScheduler; if (!sched.isShutdown()) { sched.shutdown(); } } catch (Exception e) { throw new RuntimeException(e); } } @Override public void pauseJob(String jobName, String jobGroupName) { try { quartzScheduler.pauseJob(JobKey.jobKey(jobName, jobGroupName)); } catch (SchedulerException e) { e.printStackTrace(); } } @Override public void resumeJob(String jobName, String jobGroupName) { try { quartzScheduler.resumeJob(JobKey.jobKey(jobName, jobGroupName)); } catch (SchedulerException e) { e.printStackTrace(); } } }
上面基本演示了quartz相关的一些核心代码和配置,其他的controller及jsp比较简单就不贴了...
持续学习、持续收获才能带来持续的满足和快乐!