关于quartz框架做集群定时任务调度的总结(注解配置的方式)

匿名 (未验证) 提交于 2019-12-03 00:26:01

接上文,quartz采用2.2.1版本,11张数据库的表格,

1,quartz.properties 配置文件不变(跟上文一样):

#==============================================================           #Configure Main Scheduler Properties           #==============================================================            org.quartz.scheduler.instanceName = mapScheduler         org.quartz.scheduler.instanceId = AUTO                #org.quartz.scheduler.instanceIdGenerator.class              #==============================================================           #Configure JobStore           #==============================================================          org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX         org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate         org.quartz.jobStore.tablePrefix = QRTZ_         org.quartz.jobStore.isClustered = true         org.quartz.jobStore.clusterCheckinInterval = 20000           org.quartz.jobStore.dataSource = myDS         org.quartz.jobStore.maxMisfiresToHandleAtATime = 1         org.quartz.jobStore.misfireThreshold = 120000         org.quartz.jobStore.txIsolationLevelSerializable = true                   #==============================================================           #Configure DataSource           #==============================================================      #    org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver     #    org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/sdn?useUnicode=true&characterEncoding=UTF-8     #    org.quartz.dataSource.myDS.user = root     #    org.quartz.dataSource.myDS.password =      #    org.quartz.dataSource.myDS.maxConnections = 30     #    org.quartz.jobStore.selectWithLockSQL = SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE                  #==============================================================           #Configure ThreadPool           #==============================================================          org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool         org.quartz.threadPool.threadCount = 10         org.quartz.threadPool.threadPriority = 5         org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true                  #==============================================================         #Skip Check Update         #update:true         #not update:false         #==============================================================         org.quartz.scheduler.skipUpdateCheck = true                   #============================================================================            # Configure Plugins             #============================================================================               org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin            org.quartz.plugin.shutdownhook.class = org.quartz.plugins.management.ShutdownHookPlugin         org.quartz.plugin.shutdownhook.cleanShutdown = true   

2,application-quartz.xml配置如下:(可以看到注册任务调度还是有的,实际上触发器和任务没有)

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 	xmlns:context="http://www.springframework.org/schema/context" 	xmlns:mvc="http://www.springframework.org/schema/mvc" 	xmlns:task="http://www.springframework.org/schema/task" 	 	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd         http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd          http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd ">    <!-- 新加的配置 -->      <bean id="mapScheduler" lazy-init="false" autowire="no" 		class="org.springframework.scheduling.quartz.SchedulerFactoryBean" 		destroy-method="destroy">   		<!--可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 --> 		<property name="overwriteExistingJobs" value="true" /> 		<!--必须的,QuartzScheduler 延时启动,应用启动完后 QuartzScheduler 再启动 --> 		<property name="startupDelay" value="30" /> 		<!-- 设置自动启动 --> 			<property name="autoStartup" value="true" />         <property name="jobFactory">               <bean class="com.ky.sdn.fk.server.quartz.SpringQuartzJobFactory"></bean>           </property>           <property name="dataSource" ref="dataSource"/>                    <!-- 要记得要指定配置文件的位置 -->           <property name="configLocation" value="classpath:properties/quartz.properties" />       </bean>       </beans>

3,编写一个任务注册调度监听的类,实现ApplicationListener(由springring容器管理):

import java.util.ArrayList;   import java.util.List;   import java.util.Map;   import java.util.Set;      import org.quartz.CronScheduleBuilder;   import org.quartz.CronTrigger;   import org.quartz.Job;   import org.quartz.JobBuilder;   import org.quartz.JobDetail;   import org.quartz.JobKey;   import org.quartz.Scheduler;   import org.quartz.TriggerBuilder;   import org.slf4j.Logger;   import org.slf4j.LoggerFactory;   import org.springframework.beans.factory.annotation.Autowired;   import org.springframework.context.ApplicationContext;   import org.springframework.context.ApplicationListener;   import org.springframework.context.event.ContextRefreshedEvent;   import org.springframework.core.annotation.AnnotationUtils; import org.springframework.stereotype.Component;    @Component public class QuartJobSchedulingListener implements ApplicationListener<ContextRefreshedEvent>   {       Logger logger = LoggerFactory.getLogger(QuartJobSchedulingListener.class);          @Autowired       private Scheduler scheduler;          public void onApplicationEvent(ContextRefreshedEvent event)       {           try           {               ApplicationContext applicationContext = event.getApplicationContext();               this.loadCronTriggers(applicationContext, scheduler);           }           catch (Exception e)           {               logger.error(e.getMessage(), e);           }       }          private void loadCronTriggers(ApplicationContext applicationContext, Scheduler scheduler)       {           Map<String, Object> quartzJobBeans = applicationContext.getBeansWithAnnotation(QuartzJob.class);           Set<String> beanNames = quartzJobBeans.keySet();           List<CronTrigger> cronTriggerBeans = new ArrayList<CronTrigger>();           for (String beanName : beanNames)           {               Object object = quartzJobBeans.get(beanName);               try               {                   if (Job.class.isAssignableFrom(object.getClass()))                   {                       QuartzJob quartzJobAnnotation = AnnotationUtils.findAnnotation(object.getClass(), QuartzJob.class);                       JobKey jobKey = new JobKey(quartzJobAnnotation.name(), quartzJobAnnotation.group());                       JobDetail job = JobBuilder                               .newJob((Class<? extends Job>) object.getClass())                               .withIdentity(jobKey)                               .build();                       CronTrigger cronTrigger = TriggerBuilder                               .newTrigger()                               .withIdentity(quartzJobAnnotation.name() + "_trigger", quartzJobAnnotation.group())                               .withSchedule(CronScheduleBuilder.cronSchedule(quartzJobAnnotation.cronExp()))                               .build();                       scheduler.scheduleJob(job, cronTrigger);                   }                   else                   {                       String errorMsg = object.getClass() + " doesn't implemented " + Job.class.getName();                       logger.error(errorMsg);                       throw new RuntimeException(errorMsg);                   }               }               catch (Exception e)               {                   logger.error(e.getMessage(), e);               }           }       }   }  

5,编写一个SpringBeanJobFactory 的继承类

import org.quartz.Job;   import org.quartz.spi.TriggerFiredBundle;   import org.slf4j.Logger;   import org.slf4j.LoggerFactory;   import org.springframework.beans.BeanWrapper;   import org.springframework.beans.MutablePropertyValues;   import org.springframework.beans.PropertyAccessorFactory;   import org.springframework.beans.factory.annotation.Autowired;   import org.springframework.context.ApplicationContext;   import org.springframework.scheduling.quartz.SpringBeanJobFactory; import org.springframework.stereotype.Component;    public class SpringQuartzJobFactory extends SpringBeanJobFactory   {       Logger logger = LoggerFactory.getLogger(SpringQuartzJobFactory.class);              @Autowired       private ApplicationContext ctx;          @Override       @SuppressWarnings("unchecked")       protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception       {           Job job = null;           try           {               job = ctx.getBean(bundle.getJobDetail().getJobClass());               BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(job);               MutablePropertyValues pvs = new MutablePropertyValues();               pvs.addPropertyValues(bundle.getJobDetail().getJobDataMap());               pvs.addPropertyValues(bundle.getTrigger().getJobDataMap());               bw.setPropertyValues(pvs, true);           }           catch (Exception e)           {               logger.error(e.getMessage(), e);               throw new Exception(e);           }           return job;       }   } 

6,任务定时策略的注解需要自定义去编写

import java.lang.annotation.Documented;   import java.lang.annotation.ElementType;   import java.lang.annotation.Retention;   import java.lang.annotation.RetentionPolicy;   import java.lang.annotation.Target;      import org.springframework.stereotype.Component;      @Target({ElementType.TYPE})   @Retention(RetentionPolicy.RUNTIME)   @Documented   @Component   //@Scope("prototype")   public @interface QuartzJob   {          String name();          String group() default "DEFAULT_GROUP";          String cronExp();   } 

7,编写任务类,用注解去实现定时

import java.util.Date;      import org.quartz.JobExecutionContext;   import org.quartz.JobExecutionException;   import org.springframework.scheduling.quartz.QuartzJobBean;    @QuartzJob(name = "HelloJob", cronExp = "*/10 * * * * ?")  public class HelloJob extends QuartzJobBean   {   	      @Override       protected void executeInternal(JobExecutionContext context) throws JobExecutionException       {           System.out.println("Hello Job is running @ " + new Date());           System.out.println(this.hashCode());       }        } 


总结:这种方法的注解是只能一个类写同一种定时策略的n个方法,不能一个类写不同定时策略的n个方法,就算把自定义注解改为方法的注解类型,但是QuartJobSchedulingListener这个类引用了自定义注解类,能力有限,不会改源码了,所以使用具有一点点局限性,一个类只能实现同种策略的方法。

注意:容器首次正常启动后,是不会报异常信息的,再次启动时会报异常,如下:

org.quartz.ObjectAlreadyExistsException: Unable to store Job : 'DEFAULT_GROUP.HelloJob', because one already exists with this identification.
大概意思是表中XXX已经有了数据,不能继续存储进去:

大概是说数据库已经存在了这个HelloJob,也就是容器关闭时没有删除表中信息,配置这个怎么删除我也没搞懂,但是不影响使用

还有一张表需要注意:


这里面有一些cron的表达式,因为重启容器表的数据不会清空,所以改代码的cron表达式的时候记得把job的name也改成表中没有的,这个大概跟triggerName有关系的。(上一篇纯配置实现的时候是不会出现报异常的问题的,大概是已经清空了表,这点待确认一下???)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!