有没有办法在Java中使用Quartz只运行一次作业?我知道在这种情况下使用Quartz是没有意义的。但事实是,我有多个工作,他们多次运行。所以,我正在使用Quartz。
这甚至可能吗?
您应该使用在特定时间触发而不重复的SimpleTrigger。 TriggerUtils有许多方便的方法来创建这些东西。
在quartz> 2.0中,您可以让调度程序在工作完成后取消计划任何作业:
@Override
protected void execute(JobExecutionContext context)
throws JobExecutionException {
...
// process execution
...
context.getScheduler().unscheduleJob(triggerKey);
...
}
其中triggerKey是仅运行一次的作业的ID。在此之后,不再调用该作业。
是的,这是可能的!
JobKey jobKey = new JobKey("testJob");
JobDetail job = newJob(TestJob.class)
.withIdentity(jobKey)
.storeDurably()
.build();
scheduler.addJob(job, true);
scheduler.triggerJob(jobKey); //trigger a job inmediately
以下是如何使用Quartz 2.x立即运行TestJob
类的示例:
public JobKey runJob(String jobName)
{
// if you don't call startAt() then the current time (immediately) is assumed.
Trigger runOnceTrigger = TriggerBuilder.newTrigger().build();
JobKey jobKey = new JobKey(jobName);
JobDetail job = JobBuilder.newJob(TestJob.class).withIdentity(jobKey).build();
scheduler.scheduleJob(job, runOnceTrigger);
return jobKey;
}
我不确定在Mono和Java中有多少相似的Quartz,但这似乎在.Net中有效
TriggerBuilder.Create ()
.StartNow ()
.Build ();
我不得不问自己是否有意义尝试配置一个工作并添加检查是否已按照Marko Lahma的回答中的建议运行(因为安排一个工作运行一次导致它运行一次,每次我们开始应用程序)。我发现CommandLineRunner应用程序的例子并不适用于我,主要是因为我们已经有一个ApplicationRunner用于其他使用Quartz scheduling / cron的作业。我不满意Quartz使用SimpleTrigger初始化这个工作,所以我必须找到别的东西。
使用以下文章中的一些想法:
我能够将一个工作实现拼凑在一起,这使我可以执行以下操作:
我想出了以下CommandLineRunner类:
public class BatchCommandLineRunner implements CommandLineRunner {
@Autowired
private Scheduler scheduler;
private static final Logger LOGGER = LoggerFactory.getLogger(BatchCommandLineRunner.class);
public void run(final String... args) throws SchedulerException {
LOGGER.info("BatchCommandLineRunner: running with args -> " + Arrays.toString(args));
for (final String jobName : args) {
final JobKey jobKey = findJobKey(jobName);
if (jobKey != null) {
LOGGER.info("Triggering job for: " + jobName);
scheduler.triggerJob(jobKey);
} else {
LOGGER.info("No job found for jobName: " + jobName);
}
}
}
private JobKey findJobKey(final String jobNameToFind) throws SchedulerException {
for (final JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals("DEFAULT"))) {
final String jobName = jobKey.getName();
if (jobName.equals(jobNameToFind)) {
return jobKey;
}
}
return null;
}
}
在我的一个配置类中,我添加了一个CommandLineRunner bean,它调用我创建的自定义CommandLineRunner:
@Configuration
public class BatchConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(BatchConfiguration.class);
@Bean
public BatchCommandLineRunner batchCommandLineRunner() {
return new BatchCommandLineRunner();
}
@Bean
public CommandLineRunner runCommandLineArgs(final ApplicationArguments applicationArguments) throws Exception {
final List<String> jobNames = applicationArguments.getOptionValues("jobName");
LOGGER.info("runCommandLineArgs: running the following jobs -> " + ArrayUtils.toString(jobNames));
batchCommandLineRunner().run(jobNames.toArray(ArrayUtils.EMPTY_STRING_ARRAY));
return null;
}
}
稍后,我可以通过CLI启动这些作业,而不会影响我当前的Quartz预定作业,只要没有人通过CLI多次运行命令,它就永远不会再运行。因为我接受ApplicationArguments,然后将它们转换为String [],我必须做一些类型的杂耍。
最后,我可以这样称呼它:
java -jar <your_application>.jar --jobName=<QuartzRegisteredJobDetailFactoryBean>
结果是只有在我调用它时才初始化作业,并且它被排除在我用于其他作业的CronTriggerFactoryBean触发器之外。
这里有几个假设,所以我将总结一下:
scheduler.setJobDetails(...)
)scheduler.setTriggers(...)
电话另一种解决方案:SimpleSchedulerBuilder中有一个方法.withRepeatCount(0)
:
public final int TEN_SECONDS = 10;
Trigger trigger = newTrigger()
.withIdentity("myJob", "myJobGroup")
.startAt(new Date(System.currentMillis()+TEN_SECONDS*1000)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withRepeatCount(0)
.withIntervalInMinutes(1))
.build();