WEBを動かすときに、定期的に何か処理をしたくなるときがありますよね。
例えば、他のWEBに定期的にアクセスして、自分のDBと値を同期させるとか。
定期的なバッチ処理をWEBを動かすJavaでやりたくなる理由はいくつかあると思います。
・WEBで使用しているDAOやビジネスロジックのクラスを利用したい
・WEB上でメモリに展開しているデータを使用したい
など。
この場合、linuxのクーロンや、Windowsのタスクでやろうとすると、WEBのWAR内にあるクラスを使うのは一苦労です。
クラスをバッチ用にコピーしてもいいのですが、こうすると2重管理になってしまいます。
こんなときはスケジューラ機能が便利です。
WEBでもバッチでも持っているリソース(クラスやデータ)を共同利用するには、少しクラス設計を工夫する必要がありますが、簡易な定期処理を起動することはSpringのスケジューラ機能が助けになります。
【サンプル】
<beans xmlns="http://www.springframework.org/schema/beans " xmlns:tx="http://www.springframework.org/schema/tx " xmlns:aop="http://www.springframework.org/schema/aop " xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance " xsi:schemalocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd " />
<!-- バッチサービス --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="masterDataReloadTrigger" /> </list> </property> </bean>
<!-- 起動するタイミング(時刻)の指定 --> <bean id="masterDataReloadTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="masterDataReloadJob" /> <property name="cronExpression" value="0 */30 * * * ?" /> </bean>
<!-- 実際に起動する処理の指定 --> <bean id="masterDataReloadJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="mappingDataService" /> <property name="targetMethod" value="reload" /> </bean>
<!-- 実際の処理をする自作クラスを設定する。 ここでは具体的なクラスを記述しませんがreload()メソッドを持っていることにします。 --> <bean id="mappingDataService" class="my.business.MappingDataService"> </bean>
</beans>
【説明】
上記のように、Springの設定をするだけでバッチを起動します。
しかも、単純にメソッドを起動するだけなら、特殊なクラスを継承したりする必要もありません。
<必要なフレームワーク>
Springバッチはquartzというフレームワークを必要とします。
これは、定期起動処理をするフレームワークです。
「じゃあ、これをそのまま使用すればいいじゃん!」って思うかもしれませんよね。
でも、quartzを利用するには様々なクラスを継承する必要があり、バッチ起動のためだけのクラスをいくつも作る必要があります。
それを隠蔽して簡易に利用できるようにしたのがSpringバッチです!
<起動時刻の設定>
masterDataReloadTriggerのbeanを見てください。
上記では、毎時0分、30と、30分おきに起動するようにしています。
<property name="cronExpression" value="0 */30 * * * ?" />
linuxなどのクーロンの設定をしたことがある人はおなじみの書き方だと思います。
「秒 分 時 日 月 曜日 年」
という順番で記述します。
記法例は、以下のとおり。
記述例 | 説明 |
0 0 * * * | 数値を指定する。毎時0分0秒に起動 |
0 */30 * * * | /を使用する。割り算をして余りがないときに起動。 左の場合、0分、30分。 |
0 10,15 * * * | カンマ区切りで記述する。左の場合、毎時10分0秒、15分0秒に起動する。 |
0 0 0 1 * ? */2 | ?を使用する。?は日と曜日に使用できますが、*とほぼ同じ意味です。ただ、年を指定する場合に曜日も指定しないといけなくなります。曜日を指定したくないのに*を記述すると毎日起動してしまいますので?で回避します。 左の例ですと、偶数年の毎月1日0時0分0秒に起動します。 |
0 10-15 * * * | ハイフンで記述する。左の場合、毎時10分0秒、11分0秒、~15分0秒に起動する。 |
<実施する処理の設定>
masterDataReloadJobのbeanを見てみてください。
ここで設定しています。
Springバッチが提供するMethodInvokingJobDetailFactoryBeanクラスがその役割を担っています。
設定は簡単で、起動するクラスのbean名と、メソッドを指定するだけです!
そして、こbeanは上で説明したクーロンに設定します。
簡単ですね。
<バッチの管理>
設定の一番最初にあるSchedulerFactoryBeanを見てみてください。
上記で設定したクーロンを指定しているだけです。
<property name="triggers">
<list>
<ref bean="masterDataReloadTrigger" />
</list>
</property>
これも簡単ですね
しかも、listになっているので複数設定できます。
以上で説明終わりです。
特にquartzと依存関係を持つ必要もないし、特殊なクラスを作る必要もありません。
WEBで作ったビジネスロジックをそのまま再利用できるので、大変助かります!
【補足1】
ここではquartzを使用する方法を紹介しましたが、Java's Timerを使用する方法もあるようです。
Java's TimerはJava標準の機能のようです。
【補足2】
ここからは、1年前に聞いたお話で自分で調べたわけではないので不確かな情報ですが
一応書いておきます。
どうもquartzは、ある処理が終わったら次の処理に行く、とか、複数のバッチ起動のグループがあってお互いに2重起動しないように制御するなどの様々な機能があるようです。
そして、それらの複雑な機能を使用するには、Springは貧弱で5個以上のクラスを作成してあげないといけないようです。
ですので、単純に1個の処理を起動する場合に利用するのがよさそうな感じがします。
それでも十分使いどころがあるので、便利ですよね。
参照: