JavaSEでCDIのObserversを試してみる
利用方法
- Glassfish等のJavaEE実装アプリケーションサーバを用意する。
- CDIの実装であるWeldをJavaSEで使う。
今回は、JavaSEで使ってみたいと思います。
話し変わりますが、JavaEE7 から色々なライブラリの仕様取り込んだりしてEJBが駆逐されつつあっていい感じに見える。
事前準備
<dependency> <groupId>org.jboss.weld.se</groupId> <artifactId>weld-se-core</artifactId> <version>2.4.0.Final</version> </dependency>
- パスの通っている場所にMETA-INFディレクトリおよび空のbeans.xmlを作る。
- 今回使ったプロジェクトはこちらにうp github.com
- src配下にMETA-INFディレクトリ作ってあるけど良くない気がする。(サンプルだしまぁいいか)
何ができるんじゃろか
@Observers アノテートされた引数の型とEventの型が一致した場合に勝手に通知してくれるっぽい。
試してみる
public class ObserversSample { @javax.inject.Inject javax.enterprise.event.Event<User> event; public static void main(String[] args) { Weld weld = new org.jboss.weld.environment.se.Weld(); WeldContainer container = weld.initialize(); ObserversSample obsSample = container.instance().select(ObserversSample.class).get(); obsSample.run(); } public void run() { this.event.fire(new User().name("山田").age(30)); } }
public class User { //単なるPOJOなのでgetter/setterは省略 private String name; private int age; }
public class UserEventListener { public void fire(@Observes User user) { System.out.println("Event Fire:" + user.getName()); } }
実行すると
Event Fire:山田
が出る。Eventを介して見事に通知された。楽すぎる・・・。
通知先を指定する
せっかくなので、InsertイベントとUpdateイベントで分けたい。
今のままだと、Insert用UserクラスとUpdate用Userクラスを作るか、Userクラスの中でイベントタイプを持つかしないとならないのでちょっとイケてない感がある。
ということで、Qualifier を作る。
アノテーションなので @interface で定義する。
- Insert.java
@Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface Insert {}
Eventに @Insert アノテーションを付ける。
public class ObserversSample { @Inject @Insert Event<User> insertEvent; public void run() { this.insertEvent.fire(new User().name("山田").age(30)); } }
EventListener の引数に @Insert を付与する。
public class UserEventListener { // @Insertあり public void insert(@Observes @Insert User user) { System.out.println("Insert:" + user.getName()); } // @Insert無し public void any(@Observes User user) { System.out.println("Any:" + user.getName()); } }
実行してみる
Insert:山田
@Insertのメソッドのみが通知され、@Insertなしは通知されない。
通知されたメソッドで例外が発生すると、呼び出し元に例外がthrowされてそれ以降は伝播しないもよう。