0

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);
        }
    }
}
Zim-Zam O'Pootertoot
  • 17,888
  • 4
  • 41
  • 69

1 Answers1

0

My mistake, question was already answered here inject bean reference into a Quartz job in Spring? The solution is to use a SchedulerFactoryBean and to then set its ApplicationContextSchedulerContextKey property

Community
  • 1
  • 1
Zim-Zam O'Pootertoot
  • 17,888
  • 4
  • 41
  • 69
  • That's actually not the most desirable way to solve this problem. Take a look at [my answer](http://stackoverflow.com/a/6990990/839646) on that question to see how you can achieve Spring-like dependency injection on your Quartz jobs, rather than being forced to manually retrieve beans from an ApplicationContext. – Ryan Stewart Jan 02 '13 at 19:30