接上文,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配置如下:(可以看到注册任务调度还是有的,实际上触发器和任务没有)
com.ky.sdn.fk.server.quartz.SpringQuartzJobFactory">
com.ky.sdn.fk.server.quartz.SpringQuartzJobFactory">
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
{
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 quartzJobBeans = applicationContext.getBeansWithAnnotation(QuartzJob.class);
Set beanNames = quartzJobBeans.keySet();
List cronTriggerBeans = new ArrayList();
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());
}
}
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有关系的。(上一篇纯配置实现的时候是不会出现报异常的问题的,大概是已经清空了表,这点待确认一下???)