学习使用Java Quartz任务调度(一)

本着以交流经验和学习的态度来分享知识,如果有误,请批评指出,不胜感激!

前言

现在企业中基本均有涉及到任务调度和异步执行器,在Java方向,提供了开源的Quartz、JDK提供了Timer。在以上基础前提下,Java5.0通过java.util.concurrent这个新包以及它下边的诸多类和接口,提供了方便的线程池调用。

在本篇文章中,我们主要使用Quartz来作为解决任务调度的工具。为什么不是用JDK提供的方法?
(因为Timer解决基础的调度室没有问题的,但是如果处理复杂逻辑调度和类似于每个星期一12:00处理任务,这种复杂时间,就有点捉急了)。
废话不多说,我们先做一个‘简单’的Quartz Demo来’简单’介绍一下Quartz的基本使用方法和功能
我先简单介绍一下Quartz的核心接口和类(如果已经了解的请略过):

API介绍

  • 1.Job,这是一个接口,并且只有一个void execute(JobExecutionContext context) throws JobExecutionException 的方法。这个方法定义了需要调度的方法,开发者在使用Quartz并定义调度任务时候,需要实现这个接口并且重写此方法。

  • 2.JobDetail,看名字也知道这是Job的实现类,当Quartz执行Job时,它会接受JobDetail这个实现类,通过newInstance()的反射调用机制来实例化一个Job,也就是说,在实例化Job时,需要有一个返回值来接受实例化的Job和一些静态信息。

  • 3.Trigger,这是一个类,包括两个子类,主要是触发Job执行的时间触发规则,主要有SimpleTrigger和CronTrigger两个子类;当仅需要触发一次或者以固定检核周期性执行时,SimpleTrigger一定是最合适的选择,当如果要执行复杂的调度规则时,则可以使用CronTrigger。

  • 4.Scheduler,代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,二者在Scheduler中有各自的组件、名称和组

暂时需要了解到这4样核心API,说一说我的理解就是:当你创建一个Job和Trigger之后,将这两个放到Quartz容器 Scheduler中,通过启动Scheduler来启动Job

现在,我们创建一个工程来实际使用一下

实践案例

  • 我们一步一步来,在Maven中首先引入依赖,如下图
    <dependency>
  		<groupId>org.quartz-schedulergroupId>
  		<artifactId>quartzartifactId>
  		<version>2.2.1version>
  	dependency>
  	<dependency>
  		<groupId>org.quartz-schedulergroupId>
  		<artifactId>quartz-jobsartifactId>
  		<version>2.2.1version>
  	dependency>
  	<dependency>
  		<groupId>org.slf4jgroupId>
  		<artifactId>slf4j-log4j12artifactId>
  		<version>1.6.6version>
  	dependency>
  • 然后创建一个针对RAM存储的JOB类,这个类是Job 的实现类,在实现Job接口后需要重写execute方法,在方法中定义需要执行的任务,举个例子如下
package quartz.demo;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RAMJob implements Job{

	private Logger log = LoggerFactory.getLogger(RAMJob.class);
	
	@Override
	public void execute(JobExecutionContext arg0) throws JobExecutionException {
		
		log.info("我也不知道这个啥时候执行,反正这个是Job 的实现类");
	}

}
  • 然后我们在创建一个类,用来执行一个简单的任务执行器,在新的类中我们使用main方法来启动执行,在执行之前,我们需要先定义一个JobDetail对象:
		//创建一个JobDetail
		JobDetail jobDetail = JobBuilder.newJob(RAMJob.class)
				.withDescription("调用JobDemo")
				.withIdentity("Job's name", "Job's Group")
				.build();
		log.info("描述任务:{}" + jobDetail.getDescription());

具体的任务描述和设置都已在方法中定义,不过想了解的盆友可以点开看看源码,都很简单,这里不再阐述。

  • 在定义完Job后,我们需要再定义一个Trigger触发规则,如下:
        //创建一个trigger触发规则
		Trigger trigger = TriggerBuilder.newTrigger()
				.withDescription("创建一个Trigger触发规则")
				.startAt(new Date())
				.withIdentity("Trigger's Name", "Trigger's Group")
				.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10,5))
				.build();

这里可能很多没看源码的人看不懂或者是别的情况,我简单解释一下各个方法的作用,我们通过TriggerBuilder新建一个TriggerBuilder对象。
.withDescription(String description);:根据字面意思,这个方法表示针对这个Trigger进行描述;

.startAt(Date triggerStartTime);:根据字面单词意思,这就是设置Trigger规则启动时间的方法;

.withIdentity();:这个方法是设置Trigger基本信息的方法,通过源码我们可以看到有三个重载的方法,分别是:.withIdentity(String name);.withIdentity(String name , String group);.withIdentity(TriggerKey triggerKey);,这三个方法的本身操作其实是无差别的,都是要给初始化给TriggerKey对象赋值;

  • 在完成上面两个基本任务后,我们开始构建Quartz容器,要注意一点,Quartz容器(Scheduler)是独立运行的,Scheduler可以将Trigger绑定到某一个JobDetail上,当Trigger被触发时,对应的Job就被执行,一个Job可以对应多个Trigger,一个Trigger只能对应一个Job,我们一般通过SchedulerFactory创建一个Scheduler实例;如下:
        //创建一个调度器,也就是一个Quartz容器
        //声明一个scheduler的工厂schedulerFactory
		SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        //通过schedulerFactory来实例化一个Scheduler
		Scheduler scheduler = schedulerFactory.getScheduler();
        //将Job和Trigger注册到scheduler容器中
		scheduler.scheduleJob(jobDetail,trigger);
  • 最后,我们启动scheduler容器:
    //启动容器
    log.info("JOB开始启动);
    ​
    scheduler.start();

  • 此时我们就完全启动了一个任务异步执行,启动日志如下:
10:22:35,093 [main] INFO  quartz.demo.SimpleTriggerTest  - Job开始执行
10:22:35,099 [main] INFO  quartz.demo.SimpleTriggerTest  - 描述任务:{}调用JobDemo
10:22:35,167 [main] INFO  com.mchange.v2.log.MLog  - MLog clients using log4j logging.
10:22:35,458 [main] INFO  com.mchange.v2.c3p0.C3P0Registry  - Initializing c3p0-0.9.1.1 [built 15-March-2007 01:32:31; debug? true; trace: 10]
10:22:35,482 [main] INFO  org.quartz.impl.StdSchedulerFactory  - Using default implementation for ThreadExecutor
10:22:35,494 [main] INFO  org.quartz.core.SchedulerSignalerImpl  - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
10:22:35,495 [main] INFO  org.quartz.core.QuartzScheduler  - Quartz Scheduler v.2.2.1 created.
10:22:35,496 [main] INFO  org.quartz.impl.jdbcjobstore.JobStoreTX  - Using thread monitor-based data access locking (synchronization).
10:22:35,496 [main] INFO  org.quartz.impl.jdbcjobstore.JobStoreTX  - JobStoreTX initialized.
10:22:35,497 [main] INFO  org.quartz.core.QuartzScheduler  - Scheduler meta-data: Quartz Scheduler (v2.2.1) 'dufy_test' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
  Using job-store 'org.quartz.impl.jdbcjobstore.JobStoreTX' - which supports persistence. and is not clustered.

10:22:35,497 [main] INFO  org.quartz.impl.StdSchedulerFactory  - Quartz scheduler 'dufy_test' initialized from default resource file in Quartz package: 'quartz.properties'
10:22:35,497 [main] INFO  org.quartz.impl.StdSchedulerFactory  - Quartz scheduler version: 2.2.1
10:22:35,531 [main] INFO  com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource  - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1bqrhg09w1in8fcy1gr7r0t|39a054a5, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1bqrhg09w1in8fcy1gr7r0t|39a054a5, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://140.143.205.128:3306/c_test?characterEncoding=utf8&useSSL=true, lastAcquisitionFailureDefaultUser -> null, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 10, maxStatements -> 0, maxStatementsPerConnection -> 120, minPoolSize -> 1, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
10:22:36,368 [main] INFO  org.quartz.impl.jdbcjobstore.JobStoreTX  - Freed 0 triggers from 'acquired' / 'blocked' state.
10:22:36,412 [main] INFO  org.quartz.impl.jdbcjobstore.JobStoreTX  - Recovering 0 jobs that were in-progress at the time of the last shut-down.
10:22:36,412 [main] INFO  org.quartz.impl.jdbcjobstore.JobStoreTX  - Recovery complete.
10:22:36,434 [main] INFO  org.quartz.impl.jdbcjobstore.JobStoreTX  - Removed 0 'complete' triggers.
10:22:36,455 [main] INFO  org.quartz.impl.jdbcjobstore.JobStoreTX  - Removed 0 stale fired job entries.
10:22:36,497 [main] INFO  org.quartz.core.QuartzScheduler  - Scheduler dufy_test_$_NON_CLUSTERED started.
10:22:36,497 [main] INFO  quartz.demo.SimpleTriggerTest  - Job结束
10:22:36,891 [dufy_test_Worker-1] INFO  quartz.demo.RAMJob  - 我也不知道这个啥时候执行,反正这个是Job 的实现类
10:22:40,273 [dufy_test_Worker-2] INFO  quartz.demo.RAMJob  - 我也不知道这个啥时候执行,反正这个是Job 的实现类
10:22:45,273 [dufy_test_Worker-3] INFO  quartz.demo.RAMJob  - 我也不知道这个啥时候执行,反正这个是Job 的实现类
10:22:50,269 [dufy_test_Worker-4] INFO  quartz.demo.RAMJob  - 我也不知道这个啥时候执行,反正这个是Job 的实现类
10:22:55,274 [dufy_test_Worker-5] INFO  quartz.demo.RAMJob  - 我也不知道这个啥时候执行,反正这个是Job 的实现类
10:23:00,275 [dufy_test_Worker-6] INFO  quartz.demo.RAMJob  - 我也不知道这个啥时候执行,反正这个是Job 的实现类
10:23:05,269 [dufy_test_Worker-7] INFO  quartz.demo.RAMJob  - 我也不知道这个啥时候执行,反正这个是Job 的实现类
10:23:10,272 [dufy_test_Worker-8] INFO  quartz.demo.RAMJob  - 我也不知道这个啥时候执行,反正这个是Job 的实现类
10:23:15,404 [dufy_test_Worker-9] INFO  quartz.demo.RAMJob  - 我也不知道这个啥时候执行,反正这个是Job 的实现类
10:23:20,365 [dufy_test_Worker-10] INFO  quartz.demo.RAMJob  - 我也不知道这个啥时候执行,反正这个是Job 的实现类

从日志中我们可以看出,任务是以每5s的频率执行的,执行了10个周期,与上边的定义.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10,5))的一致,任务结束

到此,一个基本的Quartz任务调度demo就结束了,下一期我们继续讲解Quartz与Spring的整合。

你可能感兴趣的:(JAVA菜鸟的学习之路,java,学习,quartz)