ファイヤープロジェクト
イベント伝播(Spring1.2.1)
2005-07-18T11:30+09:00   matsu
ApplicationContextでは,イベントを伝播する仕組みがあるらしいので,試してみた.
ApplicationContextには,イベントを伝播するためのメソッドが用意されている.
void publishEvent(ApplicationEvent event) 
このメソッドでApplicationContextは,beans.xmlに記述されたbeanの中から,org.springframework.context.ApplicationListenerの実装クラスを探し,以下のメソッド呼び出す.
void onApplicationEvent(ApplicationEvent event)
引数のeventは,publishEventの引数と一致する. ApplicationEventは,Spring組み込みのものを使用できるし,自作したものも使用できる. Spring組み込みで,かつ自動的にpublishEventされるものとして以下がある.
org.springframework.context.event.ContextRefreshedEvent
ApplicationContextが初期化あるいはリフレッシュされた際にpublishされる.
org.springframework.context.event.ContextClosedEvent
ApplicationContextがcloseされた時にpublishされる.
本頁のサンプルでは,これらのApplicationEventのリスナー(ApplicationListener)と,独自のApplicationEvent,そのリスナーを作成してみる.
以下にサンプル用に独自に作成したApplicationEventを示す.
ApplicationEventを拡張する点以外,特に制限はない. 各アプリケーションでの必要に応じて,随時何かを追加する. 本頁のサンプルでは,ApplicationListenerを二つ作成した. まず一つ目.
このクラスはSpring組み込みで自動的にpublishされるイベントを処理している. ここではinstanceofにてイベントのクラスを特定し,特定結果に応じた処理をしている. どのイベントが発生しても,全てのリスナが呼び出されるので(※),こうした処理が必要である. また,上記のようにApplicationEventには,publishした時刻とオブジェクトを返すメソッドがある.
long getTimestamp()
Object getSource()
次に二つ目.
このクラスは特にサンプル独自のイベントを処理している. やはりinstanceofにてイベントクラスを特定しているが,instanceofはリソースを多く消費するという話しもあるので,独自のイベントについてはinstanceofで分類後,何か独自の識別子(サンプルではgetNameで取得できる値)にて処理を分岐させるなどした方がよいかもしれない.
※ しかもブロッキング呼び出しなので,リスナの数や処理時間に注意する必要がある場合がある.
以下に本頁のサンプルのbeans.xmlを以下に示す.
ApplicationContextにApplicationListenerを知らせるために,これらのbeanを登録する. また,SampleBeanも作成し,登録した. サンプルでは,このbeanからイベントをpublishするが,特にそういった制限があってやっているわけではない. サンプルドライバから直接publishEventメソッドを呼び出してもよい. 以下にSampleBeanのソースを示す.
メソッドnotifySampleEventにてイベントをpublishしている.
public void notifySampleEvent() {
    logger.info("========== publish event1 ==========");
    myContext.publishEvent(new SampleEvent(this, "event1"));
    logger.info("========== publish event2 ==========");
    myContext.publishEvent(new SampleEvent(this, "event2"));
}
ApplicationContextであるmyContextは,setApplicationContextにて設定される. このsetApplictionContextメソッドは,SampleBeanがorg.springframework.context.ApplicationContextAwareを実装していることによって,ApplicationContextから自動的に呼び出される(※).
※ org.springframework.beans.factory.BeanFactoryAwareと同様.
サンプルのドライバクラスを以下に示す.
まずApplicationContextを作成,refreshする. 次にSampleBeanを取得してイベントのpublishする. 最後にApplicationContextをcloseする. では実行してみる.
$> java -jar springsample.jar 
...省略...
support.AbstractApplicationContext:444
  - Unable to locate ApplicationEventMulticaster with name
   'applicationEventMulticaster': using default
   [org.springframework.context.event.SimpleApplicationEventMulticaster@20be79]
support.AbstractBeanFactory:219
  - Creating shared instance of singleton bean 'sampleEventListener2'
support.AbstractBeanFactory:219
  - Creating shared instance of singleton bean 'sampleEventListener1'
support.DefaultListableBeanFactory:262
  - Pre-instantiating singletons in factory
   [org.springframework.beans.factory.xml.XmlBeanFactory defining beans
   [sampleEventListener2,sampleEventListener1,sampleBean]; root of BeanFactory hierarchy]
support.AbstractBeanFactory:219 - Creating shared instance of singleton bean 'sampleBean'
springsample.SampleEventListener1:20 - ContextRefreshedEvent
springsample.SampleEventListener1:26 - Mon Jul 18 11:06:30 JST 2005
springsample.SampleEventListener1:27
  - org.springframework.context.support.GenericApplicationContext: display name
   [org.springframework.context.support.GenericApplicationContext;hashCode=7804298];
    startup date [Mon Jul 18 11:06:30 JST 2005]; root of context hierarchy
springsample.SampleEventListener2:23 - else event
springsample.SampleEventListener2:25 - Mon Jul 18 11:06:30 JST 2005
springsample.SampleEventListener2:26
  - org.springframework.context.support.GenericApplicationContext: display name
   [org.springframework.context.support.GenericApplicationContext;hashCode=7804298];
   startup date [Mon Jul 18 11:06:30 JST 2005]; root of context hierarchy
springsample.SampleBean:21 - ========== publish event1 ==========
springsample.SampleEventListener1:24 - else event
springsample.SampleEventListener1:26 - Mon Jul 18 11:06:30 JST 2005
springsample.SampleEventListener1:27 - org.fireproject.springsample.SampleBean@21b220
springsample.SampleEventListener2:21 - event1
springsample.SampleEventListener2:25 - Mon Jul 18 11:06:30 JST 2005
springsample.SampleEventListener2:26 - org.fireproject.springsample.SampleBean@21b220
springsample.SampleBean:23 - ========== publish event2 ==========
springsample.SampleEventListener1:24 - else event
springsample.SampleEventListener1:26 - Mon Jul 18 11:06:30 JST 2005
springsample.SampleEventListener1:27 - org.fireproject.springsample.SampleBean@21b220
springsample.SampleEventListener2:21 - event2
springsample.SampleEventListener2:25 - Mon Jul 18 11:06:30 JST 2005
springsample.SampleEventListener2:26 - org.fireproject.springsample.SampleBean@21b220
springsample.HelloApplicationContext:38 - ========== context close ==========
support.AbstractApplicationContext:499
  - Closing application context
   [org.springframework.context.support.GenericApplicationContext;hashCode=7804298]
springsample.SampleEventListener1:22 - ContextClosedEvent
springsample.SampleEventListener1:26 - Mon Jul 18 11:06:30 JST 2005
springsample.SampleEventListener1:27
  - org.springframework.context.support.GenericApplicationContext: display name
   [org.springframework.context.support.GenericApplicationContext;hashCode=7804298];
   startup date [Mon Jul 18 11:06:30 JST 2005]; root of context hierarchy
springsample.SampleEventListener2:23 - else event
springsample.SampleEventListener2:25 - Mon Jul 18 11:06:30 JST 2005
springsample.SampleEventListener2:26
  - org.springframework.context.support.GenericApplicationContext: display name
   [org.springframework.context.support.GenericApplicationContext;hashCode=7804298];
   startup date [Mon Jul 18 11:06:30 JST 2005]; root of context hierarchy
support.AbstractBeanFactory:525 - Destroying singletons in factory
   {org.springframework.beans.factory.xml.XmlBeanFactory defining beans
   [sampleEventListener2,sampleEventListener1,sampleBean]; root of BeanFactory hierarchy}
リスナの呼び出される順番がbeans.xmlの記述した順番と一致していないことに注意. 本家ドキュメントにも特に記述が見当たらないので,リスナの呼び出し順に関する制約は設けないほうが無難だろうか.
matsu(C)
Since 2002
Mail to matsu