Quartz
でJobの定義を行うことで簡単に定期処理を記述することができますが、
デフォルトではJobにメンバ(インスタンス変数)を持たせて、それを外側からセットするのは単純にはできません。
しかし以下のようにすることで外部から必要なインスタンスをDIコンテナでInjectionすることができます。
今回のサンプルではDIコンテナにはGuice
を使用します
準備
pom.xmlにQuartz
やGuice
の依存関係を追加します
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.3</version> </dependency> <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
Jobの定義
コンストラクにInject
アノテーションを付与して、好きなクラスをインジェクションするように記述します
またJobのクラスにSingleton
アノテーションを付与しておくことで、Jobは1インスタンスが使い回しされるようになります(インスタンスが毎回生成されることはなくなります)
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import javax.inject.Inject; import javax.inject.Singleton; @Singleton public class MyJob implements org.quartz.Job { // インジェクションしたいクラス(インターフェース) private final MyLogic logic; @Inject public MyJob(MyLogic logic) { this.logic = logic } @Override public void execute(JobExecutionContext context) throws JobExecutionException { logic.invoke(); } }
Guice経由でJobを返すJobFatoryを定義する
org.quartz.spi.JobFactory
インターフェースを実装してGuiceのDIコンテナ経由でJobを返すようにnewJob
メソッドをオーバーライドします
import com.google.inject.Injector; import org.quartz.Job; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.spi.JobFactory; import org.quartz.spi.TriggerFiredBundle; import javax.inject.Inject; import javax.inject.Singleton; @Singleton final class GuiceJobFactory implements JobFactory { private final Injector injector; @Inject GuiceJobFactory(Injector injector) { this.injector = injector; } @Override public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException { JobDetail jobDetail = bundle.getJobDetail(); return injector.getInstance(jobDetail.getJobClass()); } }
SchedulerにGuice経由のJobFactoryをセットする
import org.quartz.Scheduler; public interface QuartzEx { Scheduler getScheduler(); }
import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import javax.inject.Inject; import javax.inject.Singleton; @Singleton final class QuartzExImpl implements QuartzEx { private final Scheduler scheduler; @Inject QuartzExImpl(SchedulerFactory schedulerFactory, GuiceJobFactory jobFactory) throws SchedulerException { this.scheduler = schedulerFactory.getScheduler(); this.scheduler.setJobFactory(jobFactory); this.scheduler.start(); } @Override public final Scheduler getScheduler() { return this.scheduler; } }
Quartz用のModuleの定義
AbstractModule
を継承してconfigure
メソッドをオーバーライドして定義したGuiceJobFactory
等を使用するように記述します
import com.google.inject.AbstractModule; import org.quartz.SchedulerFactory; import org.quartz.impl.StdSchedulerFactory; public final class QuartzModule extends AbstractModule { @Override protected void configure() { bind(SchedulerFactory.class).toInstance(new StdSchedulerFactory()); bind(GuiceJobFactory.class); bind(QuartzEx.class).to(QuartzExImpl.class); } }
Jobのスケジューリングを記述する
対象のJobのスケジューリングについて記述します
import com.google.inject.ImplementedBy; @ImplementedBy(TrialQuartzImpl.class) public interface TrialQuartz { void run(); }
import org.quartz.*; import javax.inject.Inject; import javax.inject.Singleton; import static org.quartz.SimpleScheduleBuilder.simpleSchedule; @Singleton public class TrialQuartzImpl implements TrialQuartz { private final QuartzEx quartz; @Inject public TrialQuartzImpl(QuartzEx quartz) { this.quartz = quartz; } @Override public void run() { JobDetail job1 = JobBuilder.newJob(MyJob.class) .withIdentity("job1", "group1") .build(); Trigger trigger1 = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(simpleSchedule() .withIntervalInMilliseconds(100) .repeatForever()) .build(); Scheduler scheduler = quartz.getScheduler(); try { scheduler.start(); scheduler.scheduleJob(job1, trigger1); } catch (SchedulerException e) { throw new RuntimeException(e); } } }
Guiceを用いてアプリケーションを実行する
Guice#createInjector
を実行する際に、Quartz用に定義したQuartzModule
のインスタンスを引数に指定します。
import com.google.inject.Guice; import com.google.inject.Injector; public class SampleLauncher { public static void main(String[] args) throws Exception { Injector injector = Guice.createInjector(new QuartzModule()); TrialQuartz trialQuartz = injector.getInstance(TrialQuartz.class); trialQuartz.run(); } }
これで無事にQuartz用のJobに対するインジェクションができます。