【Quatz】Quatz實踐
阿新 • • 發佈:2019-02-18
前言
定時任務是經常遇到的,主要有單機定時和分散式定時。今天簡單總結一下寫的幾個小例子。之後再總結quatz的原理,原始碼,其他的定時排程器等。
核心元件
- scheduler排程器
- job 任務
- trigger 觸發器
使用單純的quatz包
- pom
<!--引入quartz-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId >
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency >
- job類
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Hello Time " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss", Locale.CHINESE)));
}
}
- 主要類
public class LessonTwo {
public void run() throws Exception{
//建立排程器
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
//建立job
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("job2","group2").build();
//建立trigger
// Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger2","group2").startAt(DateBuilder.futureDate(1, DateBuilder.IntervalUnit.MINUTE)).build();
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger().withIdentity("trigger2","group2").startAt(DateBuilder.nextGivenSecondDate(null,1)).withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).withRepeatCount(3)).build();
//組裝排程器
scheduler.scheduleJob(jobDetail,trigger);
//列印
System.out.println("schduler says " + jobDetail.getKey() + " will run at" + trigger.getStartTime() + "interval " + trigger.getRepeatInterval()+ "repeatCount : "+ trigger.getRepeatCount());
//排程器開始
scheduler.start();
//排程器關閉
scheduler.shutdown();
}
}
trigger中可以定義什麼時候觸發,隔多長時間觸發一次,一共觸發幾次。
使用quatz和spring繼承的jar包
- pom
<!--quartz需要 該tx jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
單機版
- 配置檔案
<!--有基類的定時任務配置-->
<!--job配置-->
<bean id="quartzJob1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.hlp.myProject.job.quartzSimple.QuartzJob1"/>
<property name="jobDataAsMap">
<map>
<entry key="timeout" value="0"/>
</map>
</property>
</bean>
<!--trigger配置-->
<bean id="cronTrigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="quartzJob1"/>
<property name="cronExpression" value="0 0/1 * * * ? *"/>
</bean>
<!--*******************************-->
<bean id="quartzJob2" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<bean class="com.hlp.myProject.job.quartzSimple.QuartzJob2"/>
</property>
<property name="targetMethod" value="run"/>
<property name="concurrent" value="false"/>
</bean>
<bean id="cronTrigger2" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="quartzJob2"/>
<property name="cronExpression" value="0 0/1 * * * ? *"/>
</bean>
<!--單機版 排程器配置-->
<bean id="stdScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger1"/>
<ref bean="cronTrigger2"/>
</list>
</property>
</bean>
配置檔案一般是定義好一個元件1,在定義另一元件2時會引用元件1,從而繫結關係。一般這種引用用的是而不是。
- job1
/**
* 基於基類的單機版定時任務
* Created by Summer on 2018-06-30.
*/
public class QuartzJob1 extends QuartzJobBean {
private Integer timeout;
public void setTimeout(Integer timeout){
this.timeout = timeout;
}
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
LocalDateTime localDateTime = LocalDateTime.now();
String s = localDateTime.format(DateTimeFormatter.ofPattern("HH:mm:ss", Locale.CHINESE));
System.out.println(s + "基於基類QuartzJobBean的任務類開始執行了");
}
}
- job2
/**
* 沒有基類的單機版定時任務
* Created by Summer on 2018-06-30.
*/
public class QuartzJob2 {
public void run(){
LocalDateTime local = LocalDateTime.now();
String s = local.format(DateTimeFormatter.ofPattern("HH:mm:ss", Locale.CHINESE));
System.out.println(s + "沒有基類的單機版定時任務開始執行");
}
}
叢集版
- 配置檔案
<!--叢集版配置資料來源-->
<bean id="dataSourceQuartz" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${db.url_quartz}"/>
<property name="username" value="${db.username}"/>
<property name="driverClassName" value="${db.driver}"/>
<property name="password" value="${db.password}"/>
<property name="maxActive" value="${db.maxActive}"/>
<property name="initialSize" value="${db.initialSize}"/>
<property name="maxWait" value="${db.maxWait}"/>
<property name="minIdle" value="${db.minIdle}"/>
<property name="timeBetweenConnectErrorMillis" value="${db.timeBetweenEvictionRunsMillis}"/>
<property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}"/>
<property name="validationQuery" value="${db.validationQuery}"/>
<property name="testWhileIdle" value="${db.testWhileIdle}"/>
<property name="testOnBorrow" value="${db.testOnBorrow}"/>
<property name="testOnReturn" value="${db.testOnReturn}"/>
<property name="poolPreparedStatements" value="${db.poolPreparedStatements}"/>
<property name="maxOpenPreparedStatements" value="${db.maxOpenPreparedStatements}"/>
<property name="filters" value="stat,config"/>
<property name="defaultAutoCommit" value="false"/>
</bean>
<!--執行緒池任務執行器-->
<bean id="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10"/>
<property name="maxPoolSize" value="100"/>
<property name="queueCapacity" value="500"/>
</bean>
<!--把job和配置檔案綁一起-->
<bean id="quartzJob1" class="com.hlp.myProject.job.quartzSimple.QuartzJob1" />
<bean id="testMethod2" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="durability" value="true"/>
<property name="requestsRecovery" value="true"/>
<property name="jobClass" value="com.hlp.myProject.job.quartzCluster.MyDetailQuartzJobBean"/>
<property name="jobDataAsMap">
<map>
<entry key="targetObject" value="quartzJob1"/>
<entry key="targetMethod" value="executeInternal"/>
</map>
</property>
</bean>
<!--把剛才綁好和trigger綁上-->
<bean id="trigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="testMethod2"/>
<property name="cronExpression" value="0/5 * * * * ? *"/>
</bean>
<!--把資料來源和trigger綁上-->
<bean id="stdScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="dataSourceQuartz"/>
<!--延時啟動-->
<property name="startupDelay" value="30"/>
<property name="applicationContextSchedulerContextKey" value="applicationKey"/>
<property name="configLocation" value="classpath:conf/quartz.properties"/>
<property name="overwriteExistingJobs" value="true"/>
<property name="autoStartup" value="true"/>
<property name="triggers">
<list>
<ref bean="trigger1"/>
</list>
</property>
</bean>
- quatz.properties
org.quartz.scheduler.instanceName=TestScheduler1
db.driver=com.mysql.cj.jdbc.Driver
org.quartz.scheduler.instanceId=AUTO
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=10
org.quartz.threadPool.threadPriority=5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
org.quartz.jobStore.misfireThreshold=60000
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.maxMisfiresToHandleAtATime=10
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=20000
#org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
#org.quartz.dataSource.myDS.URL = jdbc:mysql://192.168.22.141:3306/dmsd_quartz?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
#org.quartz.dataSource.myDS.user = root
#org.quartz.dataSource.myDS.password = root
#org.quartz.dataSource.myDS.maxConnections = 30
#org.quartz.jobStore.selectWithLockSQL = SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE
- job
/**
* quartz分散式叢集 工廠類
* Created by Summer on 2018-06-30.
*/
/*
@PersistJobDataAfterExecution 新增到 Job 類後,表示 Quartz 將會在成功執行 execute() 方法後(沒有丟擲異常)更新 JobDetail 的 JobDataMap,下一次執行相同的任務(JobDetail)將會得到更新後的值,而不是原始的值。就像@DisallowConcurrentExecution 一樣,這個註釋基於 JobDetail 而不是 Job 類的例項。
@DisallowConcurrentExecution 不允許併發執行
*/
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
@Component
public class MyDetailQuartzJobBean extends QuartzJobBean implements ApplicationContextAware{
private static final Logger logger = LoggerFactory.getLogger(MyDetailQuartzJobBean.class);
private static ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ctx = applicationContext;
}
private String targetObject;
private String targetMethod;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try{
Object object = ctx.getBean(targetObject);
Method m = object.getClass().getMethod(targetMethod);
m.invoke(object);
}catch (Exception e){
e.printStackTrace();
logger.error("定時器異常",e);
}
}
public void setTargetObject(String targetMethod){
this.targetObject = targetObject;
}
public void setTargetMethod(String targetMethod){
this.targetMethod = targetMethod;
}
}
quatz與spring整合的特點是應用了配置檔案,三大元件及關係都配置在了配置檔案中。類中需要寫的就是一個job.
執行的時候直接點選上面的執行就可以了,因為會執行配置檔案中的邏輯。之前還一直疑惑沒有main方法從哪裡執行呢。
小結
先定義一個任務,在定義一個觸發器並把任務繫結到觸發器上,然後再定義一個總的排程器,把觸發器,任務都綁上去。這就是簡單流程了。