前言
Quartz 是一个功能强大的开源作业调度框架,用于在 Java 应用程序中执行定时任务。很多开源调度框架的底层都是依赖 quartz 库实现的。
想要快速上手这块框架,可以直接学习官方 github 中的 example 库示例:
quartz/examples at main · quartz-scheduler/quartz · GitHub
example12 包组织介绍
example12 是一个使用 quartz 客户端通过 JDK 自带的 RMI 向远程 quartz 服务端提交任务的例子,这里介绍一下正确的运行方法, 先看下代码目录:
RemoteClientExample
package quartz_test.example12;
import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This example is a client program that will remotely
* talk to the scheduler to schedule a job. In this
* example, we will need to use the JDBC Job Store. The
* client will connect to the JDBC Job Store remotely to
* schedule the job.
*
* This example demonstrates how Quartz can be used in a client/server
* environment to remotely schedule jobs on a remote server using
* RMI (Remote Method Invocation).
*
* This example will run a server that will execute the schedule. The
* server itself will not schedule any jobs. This example will also
* execute a client that will connect to the server (via RMI) to
* schedule the job. Once the job is remotely scheduled, the scheduler on
* the server will run the job (at the correct time).
*
* Note: This example works best when you run the client and server on
* different computers. However, you can certainly run the server and
* the client on the same box!
*
* Port # used for RMI connection can be modified in the example's
* property files
*
* @author James House, Bill Kratzer
*/
public class RemoteClientExample {
public void run() throws Exception {
Logger log = LoggerFactory.getLogger(RemoteClientExample.class);
// First we must get a reference to a scheduler
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
// define the job and ask it to run
JobDetail job = newJob(SimpleJob.class)
.withIdentity("remotelyAddedJob", "default")
.build();
JobDataMap map = job.getJobDataMap();
map.put("msg", "Your remotely added job has executed!");
Trigger trigger = newTrigger()
.withIdentity("remotelyAddedTrigger", "default")
.forJob(job.getKey())
.withSchedule(cronSchedule("0/5 * * ? * *"))
.build();
// schedule the job
sched.scheduleJob(job, trigger);
log.info("Remote job scheduled.");
}
public static void main(String[] args) throws Exception {
RemoteClientExample example = new RemoteClientExample();
example.run();
}
}
RemoteServerExample
/*
* All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.
* Copyright Super iPaaS Integration LLC, an IBM Company 2024
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
package quartz_test.example12;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.SchedulerMetaData;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This example demonstrates how Quartz can be used in a client/server
* environment to remotely schedule jobs on a remote server using
* RMI (Remote Method Invocation).
*
* This example will run a server that will execute the schedule. The
* server itself will not schedule any jobs. This example will also
* execute a client that will connect to the server (via RMI) to
* schedule the job. Once the job is remotely scheduled, the scheduler on
* the server will run the job (at the correct time).
* Note: This example works best when you run the client and server on
* different computers. However, you can certainly run the server and
* the client on the same box!
*
* Port # used for RMI connection can be modified in the example's
* property files
*
* @author Bill Kratzer
*/
public class RemoteServerExample {
/**
* This example will spawn a large number of jobs to run
*
* @author James House, Bill Kratzer
*/
public void run() throws Exception {
Logger log = LoggerFactory.getLogger(RemoteServerExample.class);
// First we must get a reference to a scheduler
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
log.info("------- Initialization Complete -----------");
log.info("------- (Not Scheduling any Jobs - relying on a remote client to schedule jobs --");
log.info("------- Starting Scheduler ----------------");
// start the schedule
sched.start();
log.info("------- Started Scheduler -----------------");
log.info("------- Waiting ten minutes... ------------");
// wait five minutes to give our jobs a chance to run
try {
Thread.sleep(600L * 1000L);
} catch (Exception e) {
//
}
// shut down the scheduler
log.info("------- Shutting Down ---------------------");
sched.shutdown(true);
log.info("------- Shutdown Complete -----------------");
SchedulerMetaData metaData = sched.getMetaData();
log.info("Executed " + metaData.getNumberOfJobsExecuted() + " jobs.");
}
public static void main(String[] args) throws Exception {
RemoteServerExample example = new RemoteServerExample();
example.run();
}
}
SimpleJob
package quartz_test.example12;/*
* All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.
* Copyright Super iPaaS Integration LLC, an IBM Company 2024
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
/**
* <p>
* A dumb implementation of Job, for unittesting purposes.
* </p>
*
* @author James House
*/
public class SimpleJob implements Job {
public static final String MESSAGE = "msg";
private static Logger _log = LoggerFactory.getLogger(SimpleJob.class);
/**
* Quartz requires a public empty constructor so that the
* scheduler can instantiate the class whenever it needs.
*/
public SimpleJob() {
}
/**
* <p>
* Called by the <code>{@link org.quartz.Scheduler}</code> when a
* <code>{@link org.quartz.Trigger}</code> fires that is associated with
* the <code>Job</code>.
* </p>
*
* @throws JobExecutionException
* if there is an exception while executing the job.
*/
public void execute(JobExecutionContext context)
throws JobExecutionException {
// This job simply prints out its job name and the
// date and time that it is running
JobKey jobKey = context.getJobDetail().getKey();
String message = (String) context.getJobDetail().getJobDataMap().get(MESSAGE);
_log.info("SimpleJob: " + jobKey + " executing at " + new Date());
_log.info("SimpleJob: msg: " + message);
// -Djava.rmi.server.useCodebaseOnly=false
}
}
配置文件
# Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance.
#
# Configure Main Scheduler Properties ======================================
org.quartz.scheduler.instanceName: Sched1
org.quartz.scheduler.logger: schedLogger
org.quartz.scheduler.rmi.proxy: true
org.quartz.scheduler.rmi.registryHost: localhost
org.quartz.scheduler.rmi.registryPort: 1099
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName: Sched1
org.quartz.scheduler.rmi.export: true
org.quartz.scheduler.rmi.registryHost: localhost
org.quartz.scheduler.rmi.registryPort: 1099
org.quartz.scheduler.rmi.createRegistry: true
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold: 60000
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
example12 运行方法
maven 依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz-jobs -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.3.12</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.16</version>
</dependency>
IDEA 调试
注意:客户端和服务端的 java 包名要一致,此外 SimpleJob 类是需要客户端和服务端的源码中都存在的,否则会报异常。
服务端包名: example12 代码包含:RemoteServerExample + SimpleJob + server.properties需放在 resource 目录中,并重命名为 quartz.properties
客户端包名: example12 代码包含:RemoteClientExample + SimpleJob + client.properties (需放在 resource 目录中,并重命名为 quartz.properties)
打开两个 IDEA 实例,分别运行服务端代码和客户端代码,服务端启动:
然后客户端提交任务后便退出了,日志如下:
再看服务端日志,已经收到客户端提交的任务了,就成功了: