I have a Spring singleton called CommandQueue
that I'm referencing from a Quartz Job class. When the job triggers it is supposed to enqueue a Command in the CommandQueue (calling "write()"
on a Command serializes it using Jackson, calling "Command.create(String)"
deserializes the command).
The problem I'm having is that the Job is instantiated by Quartz, not Spring, and so I can't @Autowire
a CommandQueue in the Job, nor can I get a reference to the ApplicationContext
. I also can't pass in the CommandQueue to the Job's constructor and then serialize the CommandQueue in the job's JobDataMap, because when I deserialize the CommandQueue I'd be creating a new CommandQueue instance instead of referencing the singleton.
At present I'm using a workaround in which I statically reference the CommandQueue singleton from the Job instance, but I'm wondering if there is a way to accomplish the same thing without resorting to static references.
public abstract class CommandQueue {
protected static CommandQueue queue;
public static CommandQueue queue() { return queue; }
protected CommandQueue() {}
}
@Service("CommandQueue")
@Scope(value = "singleton")
@Profile({"test"})
public class TestQueue extends CommandQueue {
public TestQueue() { CommandQueue.queue = this; }
}
@Service("CommandQueue")
@Scope(value = "singleton")
@Profile({"production"})
public class ProductionQueue extends CommandQueue {
public ProductionQueue() { CommandQueue.queue = this; }
}
@Service
@Scope(value = "singleton")
public class CommandScheduler {
private final org.quartz.Scheduler scheduler;
public CommandScheduler() {
scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
}
public JobKey scheduleRecurringSeconds(final Command command, final int seconds) {
JobDetail job = JobBuilder.newJob(CommandJob.class)
.withIdentity(command.getId()).build();
job.getJobDataMap().put("command", command.write());
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(command.getId()).startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(seconds).repeatForever())
.build();
scheduler.scheduleJob(job, trigger);
}
@DisallowConcurrentExecution
public static class CommandJob implements Job {
public void execute(JobExecutionContext context) {
String str = context.getJobDetail().getJobDataMap().get("command");
Command command = Command.create(str);
CommandQueue.queue().enqueue(command);
}
}
}