项目中往往部署多台 tomcat,但是项目中集成了quartz的话,每台tomcat中的项目都会执行,就导致了job执行多次,
quartz集群环境下,允许部署多台,但是只有一台会执行,而且一台宕机,还能有一台会执行
以下是spring boot整合quartz 集群,
quartz集群是基于数据库的,把job保存到数据库里面,执行的时候,谁先获取到 数据库的锁,就拥有了执行权限,
quartz.properties:
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
#instanceName相同,但是instanceId要不同,此处配置成自动生成
org.quartz.scheduler.instanceName = xxxClusterScheduler
org.quartz.scheduler.instanceId = AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 20
org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegate
org.quartz.jobStore.maxMisfiresToHandleAtATime=1
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
org.quartz.jobStore.selectWithLockSQL = SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE #此处的{0}不要改
#============================================================================
# Configure Datasources
#============================================================================
org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = @quartz.jdbc.url@ #此处变量来自 pom文件
org.quartz.dataSource.myDS.user = @quartz.jdbc.username@
org.quartz.dataSource.myDS.password =@quartz.jdbc.password@
org.quartz.dataSource.myDS.maxConnections = 20
org.quartz.dataSource.myDS.validationQuery=select 0 from dual
定义一个job
@Component("taskScanJob")
public class TaskScanJob {
private static Logger logger = LoggerFactory.getLogger(TaskScanJob.class);
@Autowired
private JobService jobService;
public void execute() {
System.out.println(new Date());
}
}
因为quartz的 job由spring生成,但是里面的属性没有办法自动注入,以下是解决办法
/**
* 自定义jobFactory,用于解决quartz无法注入spring属性问题
* Created by MJH on 2017/5/31.
*/
@Component("quartzJobFactory")
public class QuartzJobFactory extends SpringBeanJobFactory {
@Autowired
private AutowireCapableBeanFactory beanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object jobInstance = super.createJobInstance(bundle);
beanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
spring-quartz.xml
<bean id="taskScanJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="durability" value="true"/>
<property name="requestsRecovery" value="true"/>
<property name="jobClass" value="com.xxx.task.TaskScanJob" />
</bean>
<bean id="taskScanCronTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="taskScanJobDetail" />
<!-- 每隔1分钟执行一次 -->
<property name="cronExpression" value="0 */1 * * * ?" />
</bean>
<!-- 所有的job的触发器都写在list中 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jobFactory" ref="quartzJobFactory"/>
<property name="configLocation" value="classpath:quartz.properties" />
<property name="triggers">
<list>
<ref bean="taskScanCronTriggerBean"/>
</list>
</property>
<!-- 设置自动启动 -->
<property name="autoStartup" value="true" />
<!--QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 -->
<property name="overwriteExistingJobs" value="true"/>
springboot项目的启动类
@SpringBootApplication
@ImportResource("classpath:spring-task.xml")
@MapperScan("com.xxx.mapper")
@EnableDiscoveryClient
public class SchedulerApplication {
private static Logger logger = LoggerFactory.getLogger(SchedulerApplication.class);
public static void main(String[] args) {
SpringApplication.run(SchedulerApplication.class, args);
}
}