Spring整合quartz2.2.3总结,quartz动态定时任务,Quartz定时任务集群配置

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

©Copyright 蕃薯耀 2017年9月6日

http://www.cnblogs.com/fanshuyao/

一、Spring整合Quartz

使用的是spring4:4.3.9.RELEASE,Quartz2:2.2.3

二、引用Quartz 的Jar包

maven方式:(Spring不说了)

  1. <dependency>
  2. <groupId>org.quartz-scheduler</groupId>
  3. <artifactId>quartz</artifactId>
  4. <version>${quartz.version}</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.quartz-scheduler</groupId>
  8. <artifactId>quartz-jobs</artifactId>
  9. <version>${quartz.version}</version>
  10. </dependency>

三、在数据库创建Quartz 相关的表(下面的数据库为:tables_mysql_innodb.sql),先创建表,然后再执下面的索引,避免警告。(更多表见http://fanshuyao.iteye.com/blog/2392350)

  1. #
  2. # In your Quartz properties file, you'll need to set
  3. # org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
  4. #
  5. #
  6. # By: Ron Cordell - roncordell
  7. #  I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM.
  8. DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
  9. DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
  10. DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
  11. DROP TABLE IF EXISTS QRTZ_LOCKS;
  12. DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
  13. DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
  14. DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
  15. DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
  16. DROP TABLE IF EXISTS QRTZ_TRIGGERS;
  17. DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
  18. DROP TABLE IF EXISTS QRTZ_CALENDARS;
  19. CREATE TABLE QRTZ_JOB_DETAILS(
  20. SCHED_NAME VARCHAR(120) NOT NULL,
  21. JOB_NAME VARCHAR(200) NOT NULL,
  22. JOB_GROUP VARCHAR(200) NOT NULL,
  23. DESCRIPTION VARCHAR(250) NULL,
  24. JOB_CLASS_NAME VARCHAR(250) NOT NULL,
  25. IS_DURABLE VARCHAR(1) NOT NULL,
  26. IS_NONCONCURRENT VARCHAR(1) NOT NULL,
  27. IS_UPDATE_DATA VARCHAR(1) NOT NULL,
  28. REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
  29. JOB_DATA BLOB NULL,
  30. PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
  31. ENGINE=InnoDB;
  32. CREATE TABLE QRTZ_TRIGGERS (
  33. SCHED_NAME VARCHAR(120) NOT NULL,
  34. TRIGGER_NAME VARCHAR(200) NOT NULL,
  35. TRIGGER_GROUP VARCHAR(200) NOT NULL,
  36. JOB_NAME VARCHAR(200) NOT NULL,
  37. JOB_GROUP VARCHAR(200) NOT NULL,
  38. DESCRIPTION VARCHAR(250) NULL,
  39. NEXT_FIRE_TIME BIGINT(13) NULL,
  40. PREV_FIRE_TIME BIGINT(13) NULL,
  41. PRIORITY INTEGER NULL,
  42. TRIGGER_STATE VARCHAR(16) NOT NULL,
  43. TRIGGER_TYPE VARCHAR(8) NOT NULL,
  44. START_TIME BIGINT(13) NOT NULL,
  45. END_TIME BIGINT(13) NULL,
  46. CALENDAR_NAME VARCHAR(200) NULL,
  47. MISFIRE_INSTR SMALLINT(2) NULL,
  48. JOB_DATA BLOB NULL,
  49. PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  50. FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
  51. REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
  52. ENGINE=InnoDB;
  53. CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
  54. SCHED_NAME VARCHAR(120) NOT NULL,
  55. TRIGGER_NAME VARCHAR(200) NOT NULL,
  56. TRIGGER_GROUP VARCHAR(200) NOT NULL,
  57. REPEAT_COUNT BIGINT(7) NOT NULL,
  58. REPEAT_INTERVAL BIGINT(12) NOT NULL,
  59. TIMES_TRIGGERED BIGINT(10) NOT NULL,
  60. PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  61. FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  62. REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
  63. ENGINE=InnoDB;
  64. CREATE TABLE QRTZ_CRON_TRIGGERS (
  65. SCHED_NAME VARCHAR(120) NOT NULL,
  66. TRIGGER_NAME VARCHAR(200) NOT NULL,
  67. TRIGGER_GROUP VARCHAR(200) NOT NULL,
  68. CRON_EXPRESSION VARCHAR(120) NOT NULL,
  69. TIME_ZONE_ID VARCHAR(80),
  70. PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  71. FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  72. REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
  73. ENGINE=InnoDB;
  74. CREATE TABLE QRTZ_SIMPROP_TRIGGERS
  75. (
  76. SCHED_NAME VARCHAR(120) NOT NULL,
  77. TRIGGER_NAME VARCHAR(200) NOT NULL,
  78. TRIGGER_GROUP VARCHAR(200) NOT NULL,
  79. STR_PROP_1 VARCHAR(512) NULL,
  80. STR_PROP_2 VARCHAR(512) NULL,
  81. STR_PROP_3 VARCHAR(512) NULL,
  82. INT_PROP_1 INT NULL,
  83. INT_PROP_2 INT NULL,
  84. LONG_PROP_1 BIGINT NULL,
  85. LONG_PROP_2 BIGINT NULL,
  86. DEC_PROP_1 NUMERIC(13,4) NULL,
  87. DEC_PROP_2 NUMERIC(13,4) NULL,
  88. BOOL_PROP_1 VARCHAR(1) NULL,
  89. BOOL_PROP_2 VARCHAR(1) NULL,
  90. PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  91. FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  92. REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
  93. ENGINE=InnoDB;
  94. CREATE TABLE QRTZ_BLOB_TRIGGERS (
  95. SCHED_NAME VARCHAR(120) NOT NULL,
  96. TRIGGER_NAME VARCHAR(200) NOT NULL,
  97. TRIGGER_GROUP VARCHAR(200) NOT NULL,
  98. BLOB_DATA BLOB NULL,
  99. PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  100. INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
  101. FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  102. REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
  103. ENGINE=InnoDB;
  104. CREATE TABLE QRTZ_CALENDARS (
  105. SCHED_NAME VARCHAR(120) NOT NULL,
  106. CALENDAR_NAME VARCHAR(200) NOT NULL,
  107. CALENDAR BLOB NOT NULL,
  108. PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
  109. ENGINE=InnoDB;
  110. CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
  111. SCHED_NAME VARCHAR(120) NOT NULL,
  112. TRIGGER_GROUP VARCHAR(200) NOT NULL,
  113. PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
  114. ENGINE=InnoDB;
  115. CREATE TABLE QRTZ_FIRED_TRIGGERS (
  116. SCHED_NAME VARCHAR(120) NOT NULL,
  117. ENTRY_ID VARCHAR(95) NOT NULL,
  118. TRIGGER_NAME VARCHAR(200) NOT NULL,
  119. TRIGGER_GROUP VARCHAR(200) NOT NULL,
  120. INSTANCE_NAME VARCHAR(200) NOT NULL,
  121. FIRED_TIME BIGINT(13) NOT NULL,
  122. SCHED_TIME BIGINT(13) NOT NULL,
  123. PRIORITY INTEGER NOT NULL,
  124. STATE VARCHAR(16) NOT NULL,
  125. JOB_NAME VARCHAR(200) NULL,
  126. JOB_GROUP VARCHAR(200) NULL,
  127. IS_NONCONCURRENT VARCHAR(1) NULL,
  128. REQUESTS_RECOVERY VARCHAR(1) NULL,
  129. PRIMARY KEY (SCHED_NAME,ENTRY_ID))
  130. ENGINE=InnoDB;
  131. CREATE TABLE QRTZ_SCHEDULER_STATE (
  132. SCHED_NAME VARCHAR(120) NOT NULL,
  133. INSTANCE_NAME VARCHAR(200) NOT NULL,
  134. LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
  135. CHECKIN_INTERVAL BIGINT(13) NOT NULL,
  136. PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
  137. ENGINE=InnoDB;
  138. CREATE TABLE QRTZ_LOCKS (
  139. SCHED_NAME VARCHAR(120) NOT NULL,
  140. LOCK_NAME VARCHAR(40) NOT NULL,
  141. PRIMARY KEY (SCHED_NAME,LOCK_NAME))
  142. ENGINE=InnoDB;
  143. -- 这是是索引了--------------------------------------------
  144. CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
  145. CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
  146. CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
  147. CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
  148. CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
  149. CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
  150. CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
  151. CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
  152. CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
  153. CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
  154. CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
  155. CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
  156. CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
  157. CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
  158. CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
  159. CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
  160. CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
  161. CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
  162. CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
  163. CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
  164. commit;

四、新建一个Quartz相关的Properties文件:spring-quartz.properties,此配置为官网例子的配置

  1. #配置见:http://www.quartz-scheduler.org/documentation/quartz-2.2.x/configuration/ConfigJDBCJobStoreClustering.html
  2. #============================================================================
  3. # Configure Main Scheduler Properties
  4. #============================================================================
  5. org.quartz.scheduler.instanceName = MyClusteredScheduler
  6. org.quartz.scheduler.instanceId = AUTO
  7. #============================================================================
  8. # Configure ThreadPool
  9. #============================================================================
  10. org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
  11. org.quartz.threadPool.threadCount = 25
  12. org.quartz.threadPool.threadPriority = 5
  13. #============================================================================
  14. # Configure JobStore
  15. #============================================================================
  16. org.quartz.jobStore.misfireThreshold = 60000
  17. org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
  18. org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
  19. org.quartz.jobStore.useProperties = false
  20. org.quartz.jobStore.dataSource = myDS
  21. org.quartz.jobStore.tablePrefix = QRTZ_
  22. org.quartz.jobStore.isClustered = true
  23. org.quartz.jobStore.clusterCheckinInterval = 20000

五、整合Spring和Quartz,在Spring.xml配置

  1. <bean id="customJobFactory" class="cn.imovie.manage.task.job.CustomJobFactory"></bean>
  2. <!-- 定时任务配置 start -->
  3. <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  4. <property name="dataSource" ref="dataSource"></property>
  5. <!-- 可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 -->
  6. <property name="overwriteExistingJobs" value="true" />
  7. <!-- 必须的,QuartzScheduler 延时启动,应用启动完后 QuartzScheduler 再启动  -->
  8. <property name="startupDelay" value="2" />
  9. <!-- 设置自动启动  -->
  10. <property name="autoStartup" value="true" />
  11. <property name="jobFactory" ref="customJobFactory"></property>
  12. <property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
  13. <property name="configLocation" value="classpath:spring-quartz.properties" />
  14. </bean>
  15. <!-- 定时任务配置 end -->

其中customJobFactory 是为了解决Spring quartz Job不能依赖注入。

代码如下:

  1. import org.quartz.spi.TriggerFiredBundle;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
  4. import org.springframework.scheduling.quartz.SpringBeanJobFactory;
  5. public class CustomJobFactory extends SpringBeanJobFactory{
  6. @Autowired
  7. private AutowireCapableBeanFactory capableBeanFactory;
  8. @Override
  9. protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
  10. //调用父类的方法
  11. Object jobInstance = super.createJobInstance(bundle);
  12. //进行注入
  13. capableBeanFactory.autowireBean(jobInstance);
  14. return jobInstance;
  15. }
  16. }

六、Quartz定时任务主代码:

  1. import java.util.ArrayList;
  2. import java.util.Date;
  3. import java.util.List;
  4. import java.util.Set;
  5. import org.quartz.CronScheduleBuilder;
  6. import org.quartz.CronTrigger;
  7. import org.quartz.Job;
  8. import org.quartz.JobBuilder;
  9. import org.quartz.JobDetail;
  10. import org.quartz.JobExecutionContext;
  11. import org.quartz.JobKey;
  12. import org.quartz.Scheduler;
  13. import org.quartz.SchedulerException;
  14. import org.quartz.SimpleScheduleBuilder;
  15. import org.quartz.SimpleTrigger;
  16. import org.quartz.Trigger;
  17. import org.quartz.TriggerBuilder;
  18. import org.quartz.TriggerKey;
  19. import org.quartz.impl.matchers.GroupMatcher;
  20. import org.slf4j.Logger;
  21. import org.slf4j.LoggerFactory;
  22. import org.springframework.beans.factory.annotation.Autowired;
  23. import org.springframework.stereotype.Repository;
  24. import cn.imovie.common.utils.CC;
  25. import cn.imovie.common.utils.DateUtils;
  26. import cn.imovie.common.utils.JasonUtils;
  27. import cn.imovie.common.utils.StrUtils;
  28. import cn.imovie.dao.SchedulerManageDao;
  29. import cn.imovie.entity.task.ScheduleJob;
  30. @Repository
  31. public class SchedulerManageDaoImpl implements SchedulerManageDao{
  32. private Logger log = LoggerFactory.getLogger(SchedulerManageDaoImpl.class);
  33. @Autowired
  34. private Scheduler scheduler;
  35. /**
  36. * 新增任务
  37. * @param scheduleJob
  38. */
  39. @Override
  40. public void add(ScheduleJob scheduleJob)  throws Exception{
  41. if(!StrUtils.isBlank(scheduleJob.getCronExpression())){
  42. this.addJobCron(scheduleJob);
  43. }else{
  44. this.addJobSimple(scheduleJob);
  45. }
  46. }
  47. /**
  48. * 更新任务
  49. * @param scheduleJob
  50. */
  51. @Override
  52. public void update(ScheduleJob scheduleJob)  throws Exception{
  53. if(!StrUtils.isBlank(scheduleJob.getCronExpression())){
  54. this.updateJobCron(scheduleJob);
  55. }else{
  56. this.updateJobSimple(scheduleJob);
  57. }
  58. }
  59. /**
  60. * 新增任务
  61. * @param scheduleJob
  62. * @throws Exception
  63. */
  64. @SuppressWarnings("unchecked")
  65. @Override
  66. public void addJobCron(ScheduleJob scheduleJob) throws Exception{
  67. TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
  68. //任务触发
  69. Trigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
  70. if (null == trigger) {
  71. JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(scheduleJob.getClazz()))
  72. .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).build();
  73. jobDetail.getJobDataMap().put("scheduleJob", scheduleJob);
  74. CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
  75. /*withMisfireHandlingInstructionDoNothing
  76. ——不触发立即执行
  77. ——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
  78. withMisfireHandlingInstructionIgnoreMisfires
  79. ——以错过的第一个频率时间立刻开始执行
  80. ——重做错过的所有频率周期后
  81. ——当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行
  82. withMisfireHandlingInstructionFireAndProceed
  83. ——以当前时间为触发频率立刻触发一次执行
  84. ——然后按照Cron频率依次执行*/
  85. trigger = TriggerBuilder.newTrigger().withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).withSchedule(cronScheduleBuilder.withMisfireHandlingInstructionDoNothing()).build();
  86. scheduler.scheduleJob(jobDetail, trigger);
  87. log.info(CC.LOG_PREFIX + "新增Cron任务:"+JasonUtils.Object2String(scheduleJob));
  88. }else {
  89. // Trigger已存在,那么更新相应的定时设置
  90. //表达式调度构建器
  91. /*CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
  92. //按新的cronExpression表达式重新构建trigger
  93. trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder.withMisfireHandlingInstructionDoNothing()).build();
  94. JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
  95. JobDetail jobDetail = scheduler.getJobDetail(jobKey);
  96. jobDetail.getJobDataMap().put("scheduleJob", scheduleJob);
  97. //按新的trigger重新设置job执行
  98. scheduler.rescheduleJob(triggerKey, trigger);
  99. log.info(CC.LOG_PREFIX + "任务"+JasonUtils.Object2String(scheduleJob)+"已经存在,更新trigger");*/
  100. this.updateJobCron(scheduleJob);
  101. }
  102. }
  103. /**
  104. * 更新任务的时间表达式
  105. * @param scheduleJob
  106. */
  107. @Override
  108. public void updateJobCron(ScheduleJob scheduleJob) throws Exception{
  109. /*TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
  110. //获取trigger,即在spring配置文件中定义的 bean id="myTrigger"
  111. CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
  112. //表达式调度构建器
  113. CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
  114. //按新的cronExpression表达式重新构建trigger
  115. trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder.withMisfireHandlingInstructionDoNothing()).build();
  116. JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
  117. JobDetail jobDetail = scheduler.getJobDetail(jobKey);
  118. jobDetail.getJobDataMap().put("scheduleJob", scheduleJob);
  119. //按新的trigger重新设置job执行
  120. scheduler.rescheduleJob(triggerKey, trigger);*/
  121. //为什么要删除再新增呢?因为不这样,JobDetail的JobDataMap不更新。注解什么都试过了,没起作用。
  122. this.deleteJob(scheduleJob);
  123. this.addJobCron(scheduleJob);
  124. log.info(CC.LOG_PREFIX + "更新Cron任务(先删除再更新):"+JasonUtils.Object2String(scheduleJob));
  125. }
  126. /**
  127. * 新增任务
  128. * @param scheduleJob
  129. * @throws Exception
  130. */
  131. @Override
  132. @SuppressWarnings("unchecked")
  133. public void addJobSimple(ScheduleJob scheduleJob) throws Exception{
  134. TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
  135. //任务触发
  136. SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);
  137. if (null == trigger) {
  138. JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(scheduleJob.getClazz()))
  139. .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).build();
  140. jobDetail.getJobDataMap().put("scheduleJob", scheduleJob);
  141. SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
  142. Date triggerStartTime = new Date();
  143. if("秒".equals(scheduleJob.getTimeType()) ||
  144. "second".equalsIgnoreCase(scheduleJob.getTimeType())){
  145. simpleScheduleBuilder.withIntervalInSeconds(scheduleJob.getTimeValue());
  146. triggerStartTime = DateUtils.dateAddSeconds(triggerStartTime, scheduleJob.getTimeValue());
  147. }else if("分".equals(scheduleJob.getTimeType()) || "分钟".equals(scheduleJob.getTimeType()) ||
  148. "minute".equalsIgnoreCase(scheduleJob.getTimeType())){
  149. simpleScheduleBuilder.withIntervalInMinutes(scheduleJob.getTimeValue());
  150. triggerStartTime = DateUtils.dateAddMinutes(triggerStartTime, scheduleJob.getTimeValue());
  151. }else if("时".equals(scheduleJob.getTimeType()) || "小时".equals(scheduleJob.getTimeType()) ||
  152. "hour".equalsIgnoreCase(scheduleJob.getTimeType())){
  153. simpleScheduleBuilder.withIntervalInHours(scheduleJob.getTimeValue());
  154. triggerStartTime = DateUtils.dateAddHours(triggerStartTime, scheduleJob.getTimeValue());
  155. }else if("天".equals(scheduleJob.getTimeType()) ||
  156. "date".equalsIgnoreCase(scheduleJob.getTimeType())){
  157. simpleScheduleBuilder.withIntervalInHours(scheduleJob.getTimeValue()*24);//2017-09-15修正问题,少了24
  158. triggerStartTime = DateUtils.dateAddDays(triggerStartTime, scheduleJob.getTimeValue());
  159. }
  160. trigger = TriggerBuilder.newTrigger().withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
  161. .startAt(triggerStartTime).withSchedule(simpleScheduleBuilder.repeatForever().withMisfireHandlingInstructionNextWithRemainingCount()).build();
  162. scheduler.scheduleJob(jobDetail, trigger);
  163. log.info(CC.LOG_PREFIX + "新增简单任务:"+JasonUtils.Object2String(scheduleJob));
  164. }else {
  165. this.updateJobCron(scheduleJob);
  166. }
  167. }
  168. /**
  169. * 更新任务的时间表达式
  170. * @param scheduleJob
  171. * @throws Exception
  172. */
  173. @Override
  174. public void updateJobSimple(ScheduleJob scheduleJob) throws Exception{
  175. //为什么要删除再新增呢?因为不这样,JobDetail的JobDataMap不更新。注解什么都试过了,没起作用。
  176. this.deleteJob(scheduleJob);
  177. this.addJobSimple(scheduleJob);
  178. log.info(CC.LOG_PREFIX + "更新简单任务(先删除再更新):"+JasonUtils.Object2String(scheduleJob));
  179. }
  180. /**
  181. * 暂停任务
  182. * @param scheduleJob
  183. * @throws Exception
  184. */
  185. @Override
  186. public void pauseJob(ScheduleJob scheduleJob) throws Exception{
  187. JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
  188. scheduler.pauseJob(jobKey);
  189. log.info(CC.LOG_PREFIX + "暂停任务:"+JasonUtils.Object2String(scheduleJob));
  190. }
  191. /**
  192. * 暂停全部任务
  193. * @throws SchedulerException
  194. */
  195. @Override
  196. public void pauseAll() throws Exception{
  197. scheduler.pauseAll();
  198. log.info(CC.LOG_PREFIX + "暂停所有任务");
  199. }
  200. /**
  201. * 恢复任务
  202. * @param scheduleJob
  203. * @throws Exception
  204. */
  205. @Override
  206. public void resumeJob(ScheduleJob scheduleJob) throws Exception{
  207. JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
  208. scheduler.resumeJob(jobKey);
  209. log.info(CC.LOG_PREFIX + "恢复任务:"+JasonUtils.Object2String(scheduleJob));
  210. }
  211. /**
  212. * 恢复所有任务
  213. * @throws Exception
  214. */
  215. @Override
  216. public void resumeAll() throws Exception{
  217. scheduler.resumeAll();
  218. log.info(CC.LOG_PREFIX + "恢复所有任务");
  219. }
  220. /**
  221. * 删除任务后,所对应的trigger也将被删除
  222. * @param scheduleJob
  223. * @throws Exception
  224. */
  225. @Override
  226. public void deleteJob(ScheduleJob scheduleJob) throws Exception{
  227. JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
  228. scheduler.pauseJob(jobKey);//先暂停任务
  229. scheduler.deleteJob(jobKey);//再删除任务
  230. log.info(CC.LOG_PREFIX + "删除任务:"+JasonUtils.Object2String(scheduleJob));
  231. }
  232. /**
  233. * 立即运行任务
  234. * @param scheduleJob
  235. * @throws Exception
  236. */
  237. @Override
  238. public void triggerJob(ScheduleJob scheduleJob) throws Exception{
  239. JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
  240. scheduler.triggerJob(jobKey);
  241. log.info(CC.LOG_PREFIX + "运行任务:"+JasonUtils.Object2String(scheduleJob));
  242. }
  243. /**
  244. * 获取quartz调度器的计划任务
  245. * @return
  246. */
  247. @Override
  248. public List<ScheduleJob> getScheduleJobList(){
  249. List<ScheduleJob> jobList = null;
  250. try {
  251. GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
  252. Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
  253. jobList = new ArrayList<ScheduleJob>();
  254. for (JobKey jobKey : jobKeys) {
  255. List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
  256. for (Trigger trigger : triggers) {
  257. ScheduleJob job = new ScheduleJob();
  258. job.setJobName(jobKey.getName());
  259. job.setJobGroup(jobKey.getGroup());
  260. job.setClazz(jobKey.getClass().toString());
  261. job.setJobDesc("触发器:" + trigger.getKey());
  262. Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
  263. job.setJobStatus(triggerState.name());
  264. if (trigger instanceof CronTrigger) {
  265. CronTrigger cronTrigger = (CronTrigger) trigger;
  266. String cronExpression = cronTrigger.getCronExpression();
  267. job.setCronExpression(cronExpression);
  268. }else if(trigger instanceof SimpleTrigger){
  269. SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
  270. long milliseconds = simpleTrigger.getRepeatInterval();
  271. job.setTimeValue((int) (milliseconds/1000));
  272. }
  273. jobList.add(job);
  274. }
  275. }
  276. } catch (Exception e) {
  277. e.printStackTrace();
  278. }
  279. return jobList;
  280. }
  281. /**
  282. * 获取quartz调度器的运行任务
  283. * @return
  284. */
  285. @Override
  286. public List<ScheduleJob> getScheduleJobRunningList(){
  287. List<ScheduleJob> jobList = null;
  288. try {
  289. List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
  290. jobList = new ArrayList<ScheduleJob>(executingJobs.size());
  291. for (JobExecutionContext executingJob : executingJobs) {
  292. ScheduleJob job = new ScheduleJob();
  293. JobDetail jobDetail = executingJob.getJobDetail();
  294. JobKey jobKey = jobDetail.getKey();
  295. Trigger trigger = executingJob.getTrigger();
  296. job.setJobName(jobKey.getName());
  297. job.setJobGroup(jobKey.getGroup());
  298. job.setClazz(jobKey.getClass().toString());
  299. job.setJobDesc("触发器:" + trigger.getKey());
  300. Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
  301. job.setJobStatus(triggerState.name());
  302. if (trigger instanceof CronTrigger) {
  303. CronTrigger cronTrigger = (CronTrigger) trigger;
  304. String cronExpression = cronTrigger.getCronExpression();
  305. job.setCronExpression(cronExpression);
  306. }else if(trigger instanceof SimpleTrigger){
  307. SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
  308. long milliseconds = simpleTrigger.getRepeatInterval();
  309. job.setTimeValue((int) (milliseconds/1000));
  310. }
  311. jobList.add(job);
  312. }
  313. } catch (Exception e) {
  314. e.printStackTrace();
  315. }
  316. return jobList;
  317. }
  318. }

SchedulerManageDao接口:

  1. import java.util.List;
  2. import cn.imovie.entity.task.ScheduleJob;
  3. public interface SchedulerManageDao {
  4. /**
  5. * 新增任务
  6. * @param scheduleJob
  7. * @throws Exception
  8. */
  9. public void addJobCron(ScheduleJob scheduleJob) throws Exception;
  10. /**
  11. * 暂停任务
  12. * @param scheduleJob
  13. */
  14. public void pauseJob(ScheduleJob scheduleJob) throws Exception;
  15. /**
  16. * 暂停全部任务
  17. */
  18. public void pauseAll() throws Exception;
  19. /**
  20. * 恢复任务
  21. * @param scheduleJob
  22. */
  23. public void resumeJob(ScheduleJob scheduleJob) throws Exception;
  24. /**
  25. * 恢复所有任务
  26. */
  27. public void resumeAll() throws Exception;
  28. /**
  29. * 删除任务后,所对应的trigger也将被删除
  30. * @param scheduleJob
  31. */
  32. public void deleteJob(ScheduleJob scheduleJob) throws Exception;
  33. /**
  34. * 立即运行任务
  35. * @param scheduleJob
  36. */
  37. public void triggerJob(ScheduleJob scheduleJob) throws Exception;
  38. /**
  39. * 更新任务的时间表达式
  40. * @param scheduleJob
  41. */
  42. public void updateJobCron(ScheduleJob scheduleJob) throws Exception;
  43. /**
  44. * 获取quartz调度器的计划任务
  45. * @return
  46. */
  47. public List<ScheduleJob> getScheduleJobList();
  48. /**
  49. * 获取quartz调度器的运行任务
  50. * @return
  51. */
  52. public List<ScheduleJob> getScheduleJobRunningList();
  53. public void addJobSimple(ScheduleJob scheduleJob) throws Exception;
  54. public void updateJobSimple(ScheduleJob scheduleJob) throws Exception;
  55. /**
  56. * 如果scheduleJob.getCronExpression()表达式不为空,使用表达式方式,如果为空,则使用简单方式
  57. * @param scheduleJob
  58. */
  59. public void add(ScheduleJob scheduleJob) throws Exception;
  60. /**
  61. * 如果scheduleJob.getCronExpression()表达式不为空,使用表达式方式,如果为空,则使用简单方式
  62. * @param scheduleJob
  63. */
  64. public void update(ScheduleJob scheduleJob) throws Exception;
  65. }

七、自定义一张表,用来保存设置定时任务的时间等信息,方便取出来显示

因为Quartz定时任务设置的时间都是转为毫秒后保存的,所以当你需要将设置当时的具体时间取出来显示是还原不了的,所以创建一张自定义表保存定时任务的信息。

表主要是分为表达式和简单的时间配置2种,定时任务优化判断cron_expression是否为空,如果不为空,优先使用表达式来生成动态定时任务,如果为空,则通过获取time_value、time_type来设置定时任务。

表结构(Mysql)如下:

  1. CREATE TABLE schedule_job(
  2. schedule_job_id BIGINT PRIMARY KEY COMMENT 'ID主键' ,
  3. job_name VARCHAR(200) NOT NULL COMMENT '任务名称',
  4. job_group VARCHAR(200) NOT NULL COMMENT '任务分组',
  5. clazz VARCHAR(500) NOT NULL COMMENT '定时任务对应的类(包括包路径)',
  6. job_status VARCHAR(2) NOT NULL COMMENT '任务状态 1禁用 2启用',
  7. cron_expression VARCHAR(200)  COMMENT '任务运行时间表达式',
  8. time_value INT COMMENT '简单时间格式的值',
  9. time_type VARCHAR(50) COMMENT '简单时间格式的类型:天、时、分、秒',
  10. job_desc VARCHAR(500) COMMENT '任务描述',
  11. create_man BIGINT NOT NULL,
  12. create_time DATETIME NOT NULL,
  13. update_man BIGINT,
  14. update_time DATETIME
  15. );

对应的类(ScheduleJob)如下:

  1. import java.io.Serializable;
  2. import java.util.Date;
  3. import com.dexcoder.dal.annotation.Table;
  4. import com.dexcoder.dal.annotation.Transient;
  5. @SuppressWarnings("serial")
  6. @Table(name = "schedule_job", pkField = "scheduleJobId", pkColumn = "schedule_job_id")
  7. public class ScheduleJob implements Serializable{
  8. private Long scheduleJobId;
  9. /** 任务名称 */
  10. private String jobName;
  11. /** 任务分组 */
  12. private String jobGroup;
  13. /** 定时任务对应的类(包括包路径),如:cn.imovie.manage.task.job.TicketMoneyLessThanNormalWarn */
  14. private String clazz;
  15. /** 任务状态:1禁用 2启用*/
  16. private String jobStatus;
  17. /** 任务运行时间表达式 */
  18. private String cronExpression;
  19. /** 简单的时间值 */
  20. private Integer timeValue;
  21. /** 时间类型:秒、分、小时、天 */
  22. private String timeType;
  23. /** 任务描述 */
  24. private String jobDesc;
  25. private Long createMan;
  26. private Date createTime;
  27. private Long updateMan;
  28. private Date updateTime;
  29. // 非持久化属性
  30. private String createManText;
  31. private String updateManText;
  32. public Long getScheduleJobId() {
  33. return scheduleJobId;
  34. }
  35. public void setScheduleJobId(Long scheduleJobId) {
  36. this.scheduleJobId = scheduleJobId;
  37. }
  38. public String getJobName() {
  39. return jobName;
  40. }
  41. public void setJobName(String jobName) {
  42. this.jobName = jobName;
  43. }
  44. public String getJobGroup() {
  45. return jobGroup;
  46. }
  47. public void setJobGroup(String jobGroup) {
  48. this.jobGroup = jobGroup;
  49. }
  50. public String getClazz() {
  51. return clazz;
  52. }
  53. public void setClazz(String clazz) {
  54. this.clazz = clazz;
  55. }
  56. public String getJobStatus() {
  57. return jobStatus;
  58. }
  59. public void setJobStatus(String jobStatus) {
  60. this.jobStatus = jobStatus;
  61. }
  62. public String getCronExpression() {
  63. return cronExpression;
  64. }
  65. public void setCronExpression(String cronExpression) {
  66. this.cronExpression = cronExpression;
  67. }
  68. public Integer getTimeValue() {
  69. return timeValue;
  70. }
  71. public void setTimeValue(Integer timeValue) {
  72. this.timeValue = timeValue;
  73. }
  74. public String getTimeType() {
  75. return timeType;
  76. }
  77. public void setTimeType(String timeType) {
  78. this.timeType = timeType;
  79. }
  80. public String getJobDesc() {
  81. return jobDesc;
  82. }
  83. public void setJobDesc(String jobDesc) {
  84. this.jobDesc = jobDesc;
  85. }
  86. public Long getCreateMan() {
  87. return createMan;
  88. }
  89. public void setCreateMan(Long createMan) {
  90. this.createMan = createMan;
  91. }
  92. public Date getCreateTime() {
  93. return createTime;
  94. }
  95. public void setCreateTime(Date createTime) {
  96. this.createTime = createTime;
  97. }
  98. public Long getUpdateMan() {
  99. return updateMan;
  100. }
  101. public void setUpdateMan(Long updateMan) {
  102. this.updateMan = updateMan;
  103. }
  104. public Date getUpdateTime() {
  105. return updateTime;
  106. }
  107. public void setUpdateTime(Date updateTime) {
  108. this.updateTime = updateTime;
  109. }
  110. @Transient
  111. public String getCreateManText() {
  112. return createManText;
  113. }
  114. public void setCreateManText(String createManText) {
  115. this.createManText = createManText;
  116. }
  117. @Transient
  118. public String getUpdateManText() {
  119. return updateManText;
  120. }
  121. public void setUpdateManText(String updateManText) {
  122. this.updateManText = updateManText;
  123. }
  124. }

 八、一个定时任务Job的例子(仅供参考):这里直接使用了service的注入,默认是不可以的,需要配置customJobFactory ,上面已经有说明。

  1. import java.util.Date;
  2. import java.util.HashMap;
  3. import java.util.List;
  4. import java.util.Map;
  5. import org.quartz.DisallowConcurrentExecution;
  6. import org.quartz.Job;
  7. import org.quartz.JobExecutionContext;
  8. import org.quartz.JobExecutionException;
  9. import org.quartz.PersistJobDataAfterExecution;
  10. import org.slf4j.Logger;
  11. import org.slf4j.LoggerFactory;
  12. import org.springframework.beans.factory.annotation.Autowired;
  13. import org.springframework.stereotype.Component;
  14. import cn.imovie.common.utils.CC;
  15. import cn.imovie.common.utils.StrUtils;
  16. import cn.imovie.entity.TsCinemaBasePriceLimit;
  17. import cn.imovie.entity.warn.Warning;
  18. import cn.imovie.manage.enums.WarnType;
  19. import cn.imovie.service.TsCinemaBasePriceLimitService;
  20. import cn.imovie.service.WarningService;
  21. @Component
  22. @PersistJobDataAfterExecution
  23. @DisallowConcurrentExecution
  24. public class CinemaSalePriceGreaterThanOtherPlatformJob implements Job{
  25. private Logger log = LoggerFactory.getLogger(CinemaSalePriceGreaterThanOtherPlatformJob.class);
  26. @Autowired
  27. private TsCinemaBasePriceLimitService tsCinemaBasePriceLimitService;
  28. @Autowired
  29. private WarningService warningService;
  30. @Override
  31. public void execute(JobExecutionContext context)
  32. throws JobExecutionException {
  33. Date currentTime = new Date();
  34. Map<String, List<TsCinemaBasePriceLimit>> map = new HashMap<String, List<TsCinemaBasePriceLimit>>();
  35. try {
  36. map = tsCinemaBasePriceLimitService.listCinemaSalePriceGreaterThanOtherPlatform("1,3", currentTime);
  37. } catch (Exception e) {
  38. e.printStackTrace();
  39. }
  40. if(!StrUtils.isEmptyMap(map)){
  41. List<TsCinemaBasePriceLimit> list_2d = map.get("2d");
  42. String reason = "2D或3D销售价格高于其它平台的价格设置";
  43. for (TsCinemaBasePriceLimit tsCinemaBasePriceLimit : list_2d) {
  44. Warning warning = new Warning();
  45. warning.setWarnType(WarnType.CINEMA_SALE_PRICE_GREATER_THAN_OTHER_PLATFORM.getValue());
  46. warning.setAssociatedTable("ts_cinema_base_price_limit");
  47. warning.setAssociatedTableId(tsCinemaBasePriceLimit.getPriceLimitId());
  48. warning.setReason(reason);
  49. warning.setCreateTime(currentTime);
  50. warning.setCreateMan(-999L);
  51. warningService.save(warning);
  52. }
  53. List<TsCinemaBasePriceLimit> list_3d = map.get("3d");
  54. for (TsCinemaBasePriceLimit tsCinemaBasePriceLimit_3d : list_3d) {
  55. Warning warning = new Warning();
  56. warning.setWarnType(WarnType.CINEMA_SALE_PRICE_GREATER_THAN_OTHER_PLATFORM.getValue());
  57. warning.setAssociatedTable("ts_cinema_base_price_limit");
  58. warning.setAssociatedTableId(tsCinemaBasePriceLimit_3d.getPriceLimitId());
  59. warning.setReason(reason);
  60. warning.setCreateTime(currentTime);
  61. warning.setCreateMan(-999L);
  62. warningService.save(warning);
  63. }
  64. }
  65. log.info(CC.LOG_PREFIX + "[CinemaSalePriceGreaterThanOtherPlatformJob]定时任务执行完毕。");
  66. }
  67. }

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

©Copyright 蕃薯耀 2017年9月6日

http://www.cnblogs.com/fanshuyao/

Spring整合quartz2.2.3总结,quartz动态定时任务,Quartz定时任务集群配置的更多相关文章

  1. Spring+quartz集群配置,Spring定时任务集群,quartz定时任务集群

    Spring+quartz集群配置,Spring定时任务集群,quartz定时任务集群 >>>>>>>>>>>>>> ...

  2. springBoot集成 quartz动态定时任务

    项目中需要用到定时任务,考虑了下java方面定时任务无非就三种: 用Java自带的timer类.稍微看了一下,可以实现大部分的指定频率的任务的调度(timer.schedule()),也可以实现关闭和 ...

  3. spring整合Quartz2持久化任务调度

    转摘 https://blog.csdn.net/qwe6112071/article/details/50999386 因为通过Bean配置生成的JobDetail和CronTrigger或Simp ...

  4. Spring学习总结(18)——Spring整合Mysql数据库一主多从、多主多从配置

    一.新建jdbc.properties配置文件 master.jdbc.driverClassName=com.mysql.jdbc.Driver master.jdbc.url=jdbc:mysql ...

  5. Spring 整合 Quartz 实现动态定时任务

    复制自:https://www.2cto.com/kf/201605/504659.html 最近项目中需要用到定时任务的功能,虽然Spring 也自带了一个轻量级的定时任务实现,但感觉不够灵活,功能 ...

  6. 【转】Spring 整合 Quartz 实现动态定时任务

    http://blog.csdn.net/u014723529/article/details/51291289 最近项目中需要用到定时任务的功能,虽然spring 也自带了一个轻量级的定时任务实现, ...

  7. Spring 整合 Quartz 实现动态定时任务(附demo)

    最近项目中需要用到定时任务的功能,虽然Spring 也自带了一个轻量级的定时任务实现,但感觉不够灵活,功能也不够强大.在考虑之后,决定整合更为专业的Quartz来实现定时任务功能. 普通定时任务 首先 ...

  8. Quartz与Spring整合进行热部署的实现(一)

    先来几张实现图 任务管理页 新建任务管理.目前实现叫简单的需求...若各位同学要实现复杂的设计...quartz都有提供强大的支持.小弟目前的需求做到这已经够用了. 接下来.我们如何实现quartz的 ...

  9. Quartz动态添加,修改,删除任务(暂停,任务状态,恢复,最近触发时间)

    首页 博客 学院 下载 图文课 论坛 APP 问答 商城 VIP会员 活动 招聘 ITeye GitChat 写博客 小程序 消息 登录注册 关闭 quartz_Cron表达式一分钟教程 09-05 ...

随机推荐

  1. 给Libgdx的ShapeRenderer开启抗锯齿

    http://blog.rpsg-team.com/?p=134 ——————————————————————————————————————————————————————————————————— ...

  2. 快速排序算法(Quicksort)

    快速排序算法是对集合中元素进行排序最通用的算法,俗称快排,其算法的时间复杂度为O(nlgn),空间复杂度为O(1). 我们举例来对其算法思路进行理解,譬如数组 A = { 4, 8, 1, 2, 9, ...

  3. R语言如何将字符串转变为命令执行

    这里用到 eval() 和 parse() 函数.首先使用 parse() 函数将字符串转化为表达式(expression),而后使用 eval() 函数对表达式求解.x <- 1:10a &l ...

  4. 【Qt开发】QThread 实用技巧、误区----但文档中没有提到

    本文主要内容: 在任务一中,用 四 种方式实现:点击界面按钮,开线程运行一段程序,结果显示在一个Label上.1. 用不正确的方式得到看似正确的结果2. 用Qt Manual 和 例子中使用的方法3. ...

  5. ADT安装

    Eclipse安装ADT很简单,直接把下载好的ADT文件解压,覆盖到eclipse目录下的features和plugins目录即可, MyEclipse配置就稍微麻烦了点,我刚开始配置了好几次都不成功 ...

  6. 一个类似于postman的协议测试工具

    协议测试工具使用postman相当便捷,不过有一个问题,就是每个人都要装一个这个东西,并且测试文件导来导去,还是觉得麻烦了点. 最重要的是postman不能修改,有一些定制功能postman明显力不从 ...

  7. c# 阿拉伯数字转成中文

    调用方法: public string ConvertToChineseNumber(string old) { Chinese ch = new Chinese(); long num = Conv ...

  8. Redis系列-php怎么通过redis扩展使用redis

    From: http://blog.csdn.net/love__coder/article/details/8691679 通过前面几篇blog,我们应该对redis有个大致的认识,这里再讲解下,p ...

  9. php 变量定义方法

    1.定义常量define("CONSTANT", "Hello world."); 常量只能包含标量数据(boolean,integer,float 和 str ...

  10. 解决 PathVariable annotation was empty on param 0.

    今天在写网关关于远程调用Feign的时候报的一个错误,PathVariable注解为空.仔细看了一下代码发现问题出在用@PathVariable注解的时候 @PathVariable Integer ...