コンテンツ一覧 †J2EEコンテナであるJBossを使ってEJBの勉強をしてみました。以下、作業メモです。 EJBの使い方 †例えば、sayHello()メソッドでStringを返却するEJBを作る場合以下の物が必要です。
これとさまざまなDD(Deployment Descriptor)ファイルを作成し、コンテナにデプロイしておくことで、ビジネスロジックを使用したいヒト(プログラム)は、
このようにすることによって、ビジネスロジックがどこで実行されたかを気にしないで結果を得ることができるようになります。つまり可用性が向上するわけですね。 まずはJNDI名と、EJBたちの関係 †さて、先ほどJNDI経由でHomeインタフェースを取得すると言いましたが、EJBではオブジェクトを取得する際、必ずInitialContext?を経由します。この機構をJNDIといいます。InitialContext?はあらかじめ、Stringのキー値とオブジェクトを対にしてコンテナに登録しておき、そのキー値でオブジェクトを検索し取得するのですが、そのキー値とオブジェクトの関係を理解しないと相当ややこしいです。 先の例で行くと、 initContext = new InitialContext(); Object ref = initContext.lookup("HelloEJBHoge"); HelloHome home = (HelloHome) PortableRemoteObject.narrow(ref,HelloHome.class); とルックアップするのですが、この"HelloEJBHoge"がキー値で、HelloHome? が登録されているオブジェクトです。 話を整理すると、
ということです。そこでそもそもコンテナにオブジェクトを登録する方法は?、もっと具体的にいうとInitialContext?をlookupする際のキー"HelloEJBHoge"と、hello.HelloHome?オブジェクトはどうやって関連づけられるのでしょうか??という疑問がわき起こります。 考察 †さて先の疑問を解決したいと思います。まだTry and Errorですが。。。 まず、hello.HelloHome?に名前を付けます。これはJ2EEの仕様内であるejb-jar.xmlによって行われます。 <?xml version="1.0"?> <!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN' 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'> <ejb-jar> <enterprise-beans> <session> <ejb-name>HelloEJB</ejb-name> <home>hello.HelloHome</home> <-ココ <remote>hello.Hello</remote> <ejb-class>hello.HelloBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> </session> </enterprise-beans> </ejb-jar> これで、hello.HelloHome?にはHelloEJBというEJB名が付けられました。 さらに、このEJB名"HelloEJB"とコンテナ側に登録されている"HelloEJBHoge"は、JBoss独自ファイルである、jboss.xmlで関連づけられます。*2 <?xml version="1.0"?> <jboss> <enterprise-beans> <session> <ejb-name>HelloEJB</ejb-name> <jndi-name>HelloEJBHoge</jndi-name> </session> </enterprise-beans> </jboss> これでHelloEJBHogeというキーとhello.HelloHome?が関連づけられました。これらのクラスファイルやDDファイルをコンテナにデプロイすることで、JNDIへの登録から何からが完了したことになります。ちなみにejb-jar.xmlとjboss.xmlはejbのjarの/META-INF内に配置します。 ようやくこれで、HelloEJBHogeでlookupすればhello.HelloHome?を取得できそうです。実際にやってみると public static void main(String[] args) throws NamingException, RemoteException, CreateException { InitialContext initContext = null; try { initContext = new InitialContext(); Object ref = initContext.lookup("HelloEJBHoge"); HelloHome home = (HelloHome) PortableRemoteObject.narrow(ref, HelloHome.class); Hello hello = home.create(); System.out.println(hello.sayHello()); } finally { if (initContext != null) { initContext.close(); } } } これで確かに稼動しました!。ちなみにEclipseから実行したときは、実行時のクラスパスに${JBOSS_HOME}/client/jbossall-client.jarにパスを通さないとダメみたい。。 javax.naming.NoInitialContextException: Cannot instantiate class: org.jnp.interfaces.NamingContextFactory [Root exception is java.lang.ClassNotFoundException: org.jnp.interfaces.NamingContextFactory] at javax.naming.spi.NamingManager.getInitialContext(Unknown Source) at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source) at javax.naming.InitialContext.init(Unknown Source) なんてエラーが表示されしまうかも。。。 クライアントからではなく、サーブレットなどからアクセスする †さて、いわゆるローカルな(?)Lookupはこれで良さそうですが、サーブレットなどからEJBにアクセスするためにはjava:comp/envを使ったENCによるJNDI検索をする必要があるみたいです。つまりInitialContext?をlookupするときに context.lookup("java:comp/env/ejb/HelloEJB"); てやる例のヤツです。 さて、 context.lookup("java:comp/env/ejb/HelloEJB"); と指定すると、web.xml内のejb-refを ejb/HelloEJB で検索します。web.xmlには以下のEJB参照を記述しました。。 <ejb-ref> <ejb-ref-name>ejb/HelloEJB</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <home>hello.HelloHome</home> <remote>hello.Hello</remote> <ejb-link>HelloEJB</ejb-link> </ejb-ref> これで、ejb-linkのところでjboss.xmlのejb-nameを見に行って、そこのjndi-nameでlookupする、と理解したんだけど、うまくいかない。。。。。。以下のエラーが表示されてしまいます。 EJBException in method: public abstract hello.Hello hello.HelloHome.create() throws java.rmi.RemoteException,javax.ejb.CreateException: javax.ejb.EJBException: Invalid invocation, check your deployment packaging, method=public abstract hello.Hello hello.HelloHome.create() throws java.rmi.RemoteException,javax.ejb.CreateException でも、わざと <ejb-link>HelloEJB</ejb-link> をjboss.xmlにないHelloEJBaとかすると javax.naming.NamingException: ejb-ref: ejb/HelloEJB, no ejb-link in web.xml and no jndi-name in jboss-web.xml) なんていわれるから、DDたちはあってるような気がする。。。 また、ENCを使わないでクライアントでやったように直接 Object boundObject = context.lookup("HelloEJBHoge"); とやっても、ENCでやったときと同じエラーが出ちゃいます。
jboss-web.xmlを使う †JBossでは先に書いた <ejb-link>HelloEJB</ejb-link> とjboss.xmlのejb-nameによるJNDI名との関連づけだけではなく、jboss-web.xmlによる関連づけも可能です。たぶんweb.xmlにはejb-linkを書かないで、jboss-web.xmlに <ejb-ref> <ejb-ref-name>ejb/HelloEJB</ejb-ref-name> <jndi-name>HelloEJBHoge</jndi-name> </ejb-ref> と書くだけのようです。こっちの方が、きれいですね。ちなみにjboss-web.xmlはwarのWEB-INF/直下に配置します。web.xmlの隣に置いておきましょう。
関連リンク †
この記事は
現在のアクセス:27699 |