Spring boot + Quartz實現分散式定時任務
阿新 • • 發佈:2019-02-12
在實際專案中經常會用到定時任務,且有些定時任務同時只能執行一個例項,下面介紹一下通過Spring boot + Quartz框架實現分散式定時任務。
1. 定時任務持久化到Mysql
2. 名稱為JobA的定時任務每10秒執行一次@ScheduledJob(name = “JobA”, cronExp = “/10 * * * ?”)
3. @DisallowConcurrentExecution同一個定時任務同一時間只能有一個執行,如果定時任務執行時間超過10秒,丟棄或等待(未驗證)
4. 此定時任務可以同時部署多個,支援Failover
5. Quartz相關SQL請參考https://github.com/465919283/demo/blob/master/sql/quartz.sql
quartz.properties
org.quartz.scheduler.instanceName=spring-boot-quartz
org.quartz.scheduler.instanceId=AUTO
org.quartz.threadPool.threadCount=5
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz .jobStore.useProperties=false
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered=true
import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
public class QuartzConfig {
public static final String QUARTZ_PROPERTIES_PATH = "quartz.properties";
@Autowired
private DataSource dataSource;
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public JobFactory jobFactory(ApplicationContext applicationContext) {
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setAutoStartup(true);
factory.setJobFactory(jobFactory);
factory.setQuartzProperties(quartzProperties());
//使用Spring boot中配置的資料來源
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
return factory;
}
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource(QUARTZ_PROPERTIES_PATH));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ScheduledJob {
String name();
String group() default "DEFAULT_GROUP";
String cronExp();
}
import org.quartz.CronScheduleBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
@Component
public class ScheduleListener implements BeanPostProcessor {
@Autowired
private Scheduler scheduler;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
ScheduledJob scheduledJob = AnnotationUtils.findAnnotation(bean.getClass(), ScheduledJob.class);
if (scheduledJob != null && bean instanceof Job) {
JobKey jobKey = new JobKey(scheduledJob.name(), scheduledJob.group());
JobDetail jobDetail = JobBuilder.newJob(((Job) bean).getClass())
.withIdentity(jobKey)
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(scheduledJob.name() + "Trigger", scheduledJob.group())
.forJob(jobDetail)
.withSchedule(CronScheduleBuilder.cronSchedule(scheduledJob.cronExp()))
.build();
try {
if (!scheduler.checkExists(jobKey)) {
scheduler.scheduleJob(jobDetail, trigger);
}
} catch (SchedulerException e) {
e.printStackTrace();
}
}
return bean;
}
}
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Component;
import com.primer.demo.task.ScheduledJob;
@Component
@ScheduledJob(name = "JobA", cronExp = "*/10 * * * * ?")
@DisallowConcurrentExecution
public class JobA implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
System.out.println("JobA................");
}
}