Guice-Quartz integration
GuiceとQuartzのintegrationを書いてみました。 CronTriggerのみの実装です。
Jobをimplementsしたinterfaceにannotationを書だけで定期的にメソッドが呼ばれるようになります。
見たほうが早いのでとりあえずソース。
呼び出すinterface。
package net.nagaseyasuhito.sandbox.worker; import net.nagaseyasuhito.sandbox.guice.Scheduled; import net.nagaseyasuhito.sandbox.worker.impl.SandboxWorkerImpl; import org.quartz.Job; import com.google.inject.ImplementedBy; @ImplementedBy(SandboxWorkerImpl.class) @Scheduled(expression = "0 * * * * ?") public interface SandboxWorker extends Job { }
実装クラス。
package net.nagaseyasuhito.sandbox.worker.impl; import net.nagaseyasuhito.sandbox.worker.SandboxWorker; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import com.wideplay.warp.persist.Transactional; public class SandboxWorkerImpl implements SandboxWorker { @Override @Transactional public void execute(JobExecutionContext context) throws JobExecutionException { // do something } }
このinterfaceをguiceに登録し、QuartzService.start()を呼びます。
Module quartzModule = QuartzService. usingAnnotation(). add(SandboxWorker.class). buildModule(); Injector injector = Guice.createInjector(quartzModule); injector.getInstance(QuartzService.class).start();
Quartzの設定がすっきりします。お試しあれ。
GuiceのModule
package net.nagaseyasuhito.sandbox.guice; import java.text.ParseException; import java.util.HashSet; import java.util.Set; import org.quartz.CronTrigger; import org.quartz.Job; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.TriggerListener; import org.quartz.impl.StdSchedulerFactory; import org.quartz.spi.JobFactory; import org.quartz.spi.TriggerFiredBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.inject.AbstractModule; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Module; public class QuartzService { private static final Logger log = LoggerFactory.getLogger(QuartzService.class); public static QuartzService usingAnnotation() { return new QuartzService(); } @Inject private Injector injector; private Scheduler scheduler; private QuartzService() { try { this.scheduler = new StdSchedulerFactory().getScheduler(); this.scheduler.addGlobalTriggerListener(new TriggerListener() { private Set<String> runningJobs = new HashSet<String>(); @Override public String getName() { return this.getClass().getName(); } @Override public void triggerComplete(Trigger trigger, JobExecutionContext context, int instructionCode) { synchronized (this.runningJobs) { this.runningJobs.remove(context.getJobDetail().getFullName()); } } @Override public void triggerFired(Trigger trigger, JobExecutionContext context) { } @Override public void triggerMisfired(Trigger trigger) { } @Override public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) { synchronized (this.runningJobs) { if (this.runningJobs.contains(context.getJobDetail().getFullName())) { return true; } else { this.runningJobs.add(context.getJobDetail().getFullName()); return false; } } } }); this.scheduler.setJobFactory(new JobFactory() { @SuppressWarnings("unchecked") public Job newJob(TriggerFiredBundle bundle) throws SchedulerException { JobDetail jobDetail = bundle.getJobDetail(); Class<? extends Job> jobClass = jobDetail.getJobClass(); try { return QuartzService.this.injector.getInstance(jobClass); } catch (Exception e) { throw new SchedulerException("Problem instantiating class '" + jobDetail.getJobClass().getName() + "'", e); } } }); } catch (SchedulerException e) { QuartzService.log.error("QuartzService initialize failed", e); } } public QuartzService add(Class<? extends Job> clazz) { Scheduled scheduled = clazz.getAnnotation(Scheduled.class); if (scheduled != null) { try { Trigger trigger = new CronTrigger(clazz.getCanonicalName(), scheduled.group(), scheduled.expression()); JobDetail job = new JobDetail(clazz.getCanonicalName(), scheduled.group(), clazz); this.scheduler.scheduleJob(job, trigger); } catch (ParseException e) { QuartzService.log.error("CronTrigger expression parse failed(" + scheduled.expression() + "). skipped", e); } catch (SchedulerException e) { QuartzService.log.error("job scheduling failed. skipped", e); } } return this; } public Module buildModule() { return new AbstractModule() { @Override protected void configure() { this.bind(QuartzService.class).toInstance(QuartzService.this); } }; } public void shutdown() { if (this.scheduler != null) { try { this.scheduler.shutdown(true); } catch (SchedulerException e) { QuartzService.log.error("QuartzService shutdown failed", e); } } } public void start() { try { this.scheduler.start(); } catch (SchedulerException e) { QuartzService.log.error("QuartzService start failed", e); } } }
呼び出すinterfaceに書くannotation。
package net.nagaseyasuhito.sandbox.guice; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Scheduled { String expression(); String group() default "default"; }