S-JIS[2008-08-03/2008-09-27] 変更履歴

EJB3.0

EJB(Enterprise Java Beans)3.0は、アノテーションを使うことでxmlファイルを書く必要が無くなり、EJB2.Xよりも扱うのが簡単になった。
(EJB3.0はJavaEE5(1.5)の仕様のひとつ)


ステートレスセッションビーンの実験

WebLogic10.0JBoss4.2.3でステートレスビーンを試してみた。

EJBの呼び出しで使われるインターフェース:

package sample.ejb3.stateless;

import javax.ejb.Local;
import javax.ejb.Remote;

@Remote付けられるアノテーションの組み合わせ
@Local
public interface Ejb3Sample {

	public void execute(String text);
}

インターフェースは、何の変哲も無い普通(POJI)のインターフェース。
自分で呼び出したいメソッドを宣言する。
また、このメソッドを@Statelessアノテーション付きのクラスでimplementsする。

EJB本体(呼び出される側)

package sample.ejb3.stateless;

import javax.ejb.Stateless;

@Stateless(	→付けられるアノテーションの組み合わせ
//WLS10.0Jの場合
//	name = "ejb3sample",		…あっても無くても関係無さそう
//	description = "EJB3サンプル",	…あっても無くても関係無さそう
	mappedName = "ejb3_sample"

//JBoss4.2.3の場合
	name = "sample/Ejb3SampleBean"
)
public class Ejb3SampleBean implements Ejb3Sample {

	//インターフェースEjb3Sampleの実装
	public void execute(String text) {
		// WebLogicのコンソールに出力される
		System.out.println("Ejb3SampleBean#exec:" + text);
	}
}

EJB3.0では、EJBの定義にアノテーションを使用する。このアノテーションを付けておけば、ejb-jar.xmlだの何だのは何も記述しなくてよい。
javax.ejbパッケージを使う為には、そのクラスが入っているjarファイルをクラスパスに加える必要がある。

WLS10では@Remote・@LocalアノテーションBean側に付けてもインターフェース側に付けても動作はするが、Javadocを見るとインターフェースに付けるのが正しいような気がする。[2008-08-14]
付けられるアノテーションの組み合わせ

これらのクラスをコンパイルしてデプロイすれば、呼び出せるようになる。[/2008-08-15]
WLS10.0JのEJB3のデプロイ
JBoss4.2.3のEJB3のデプロイ


呼び出し側は以下のようにコーディングする。

import javax.naming.Context;
import javax.naming.NamingException;

import sample.ejb3.stateless.Ejb3Sample; //EJB呼び出し用のインターフェース

public class Ejb3SampleBatch {

	public static void main(String[] args) throws NamingException {

		Context ctx = initContext(); //APサーバー毎に異なる

		Ejb3Sample sample;
		try {
			sample = (Ejb3Sample) ctx.lookup("ejb3_sample#" + Ejb3Sample.class.getName());	//WLS10.0J
			sample = (Ejb3Sample) ctx.lookup("sample/Ejb3SampleBean/remote");		//JBoss4.2.3
							→JNDI名の違い
		} finally {
			ctx.close();
		}

		sample.execute("バッチから呼び出し");
	}

	〜
}

APサーバー(WebLogic(ドメイン)JBossAS)が稼動している状態で普通に上記クラスを実行すればEjb3SampleBeanが呼び出せる。

サーブレットから実行する場合は、コンテキストの取得を「Context ctx = new InitialContext();」とすればいいだけ。(JMSの例と同じ)


APサーバー毎の違い

JBossでもWebLogicと同じようにEJB3.0のアノテーションを試してみたところ、設定した内容の反映のされ方が違ってハマった。[2008-08-15]

  EJBデプロイ方法 JNDI確認方法 リモートInitialContext その他
WLS 10.0J autodeploy/my_ejb JNDIツリー WLInitialContextFactory  
JBoss 4.2.3 deploy/my_ejb.jar JNDIView NamingContextFactory EJB名はGlobal JNDIになる。
  インターフェース ビーン本体 lookup JNDI名 備考
WLS 10.0J
package jp.sample;

@Remote
@Local
public interface Sample
@Stateless(
mappedName = "mapName"
)
public class Bean
ctx.lookup(
 "mapName#" +
 Sample.class.getName()
)
mapName#jp/sample/Sample @Remoteと@Localを両方ともインターフェースに付ける事が出来る。
package jp.sample;

public interface Sample
@Stateless(
mappedName = "mapName"
)
@Remote
@Local
public class Bean
ctx.lookup(
 "mapName#" +
 Sample.class.getName()
)
mapName#jp/sample/Sample @Remoteと@Localを両方ともビーン側に付ける事が出来る。
JBoss 4.2.3
@Remote
public interface Sample
@Stateless(
name = "jp/sample/Sample"
)
@Local
public class Bean
ctx.lookup(
 "jp/sample/Sample/local"
)
ctx.lookup(
 "jp/sample/Sample/remote"
)
jp/sample/Sample/local
jp/sample/Sample/remote
JBossでは、インターフェース又はビーンのどちらか一方に@Remoteと@Localを同時に付けるとエラーになる。
また、インターフェースに@Local・ビーンに@Remoteを付けてもエラーになる。
@Remote
public interface Sample
@Stateless
@Local
public class Bean
ctx.lookup(
 "Bean/local"
)
ctx.lookup(
 "Bean/remote"
)
Bean/local
Bean/remote
@Statelessにnameを付けないと、ビーンのクラス名(パッケージ無し)になる。
@Remote
public interface Sample
@Stateless
public class Bean
ctx.lookup(
 "Bean/remote"
)
Bean/remote @Remoteか@Localのどちらかしか指定しないと、そちらだけJNDIに登録される。
@Local
public interface Sample
@Stateless
public class Bean
ctx.lookup(
 "Bean/local"
)
Bean/local

JBossの場合、earファイル化したEJBでは、JNDI名の先頭にearファイル名が付く。[2008-09-27]
つまりtest.earに入っているfoo.jarで「@Stateless(name = "jp/sample/Sample")」の場合、「ctx.lookup("test/jp/sample/Sample/local")」となる。


メッセージ駆動ビーンの実験

メッセージ駆動(メッセージドリブン)型EJBは、JMS経由で送られてくるメッセージを受け取る。
つまり、JMSのキューにメッセージが入れられると、用意したメッセージ駆動ビーン(Message Driven Bean:MDB)のonMessage()が呼ばれる。

package sample.ejb3.mdb;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@MessageDriven(
//WLS10.0Jの場合
	mappedName = "MyQueue0"

//JBoss4.2.3の場合
	activationConfig = {
		@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
		@ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/MyQueue1")
	}
)
public class MdbSampleBean implements MessageListener {

	// MessageListenerのメソッドを実装
	public void onMessage(Message msg) {
		try {
			System.out.println("MDBで受け取った:" + msg);
			if (msg instanceof TextMessage) {
				TextMessage tm = (TextMessage) msg;
				System.out.println(tm.getText());
			}
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}
}

mappedNameactivationConfigには、あらかじめAPサーバーに登録しておいたキューのJNDI名を指定する。

コンパイルしてデプロイする手順はステートレスセッションビーンEJB本体と同様。
(JBoss4.2.3の場合、javax.jmsの為にJBOSS_HOME/server/default/lib/jboss-j2ee.jarが必要。[2008-08-16]

APサーバー(WebLogicのドメインJBoss)を実行すると、このビーンはEJBコンテナに登録されて、待機に入る。[2008-08-04]
JMSのキューメッセージが入れられると、当ビーンのインスタンスが作られてonMessage()が呼ばれる。
実行間隔が長ければ同じインスタンスが繰り返し使われるが、処理が終わらないうちに次のメッセージが来ると、新しいインスタンスが作られてそれが呼ばれる。
すなわちマルチスレッドで動作するので、EJBはスレッドセーフな作りにしなければならない。


POJOPOJI

POJOとは、Plain Old Java Objectのこと。[2008-08-24]
POJIとは、Plain Old Java Interfaceのこと。

要するに従来型のシンプルな(普通の)Javaのクラス・インターフェースのこと。
その反対は、EJB2のような、XMLファイルに定義を書く必要があるような複雑な定義方法をするクラス。 (XMLファイルに定義を書かないと動作させられないようなクラス)

EJB3.0ではPOJOやPOJIに対してアノテーションを付けるだけでよく、XMLファイルを書く必要がない(というが売り文句)。


参考:


JavaEEへ戻る / Java目次へ戻る / 新機能へ戻る
メールの送信先:ひしだま