第29章 JBoss 上の EJB
EJB コンテナー設定とアーキテクチャー
JBoss EJB コンテナーのアーキテクチャーは、モジュール式のプラグインアプローチを採用しています。EJB コンテナーの主なアスペクトを開発者がカスタマイズしたプラグインやインターセプターで置き換えることが可能です。このアプローチは、ニーズにあわせて EJB コンテナー動作のカスタマイズを微調整することができます。EJB コンテナー動作のほとんどが EJB JAR
META-INF/jboss.xml 記述子やデフォルトのサーバー全体で対応する standardjboss.xml 記述子を使い設定が可能です。コンテナーアーキテクチャーについて学習していくとともに、この章全体で様々な設定機能を見ていきます。
29.1. EJB クライント側のビュー
EJB コンテナーの説明ですが、ホームおよびリモートプロキシを使った EJB のクライアントビューについてまず見ていきます。コンテナープロバイダーがEJB 実装向けに
javax.ejb.EJBHome および javax.ejb.EJBObject を生成します。クライアントは、EJB bean インスタンスを直接参照するわけではなく、bean ホームインターフェースを実装する EJBHome と bean リモートインターフェースを実装する EJBObject を参照します。図29.1「JBoss における EJBHome プロキシの構成」 では、EJB ホームプロキシの構成と EJB デプロイメントとの関係について説明しています。

図29.1 JBoss における EJBHome プロキシの構成
この図で番号付きの項目は以下のとおりです。
- EJBDeployer (
org.jboss.ejb.EJBDeployer) を呼び出し、EJB JAR をデプロイします。EJBModule(org.jboss.ejb.EJBModule) を作成し、デプロイメントメタデータをカプセル化します。 EJBModuleライフサイクルの作成フェーズで、EJBModuleinvoker-proxy-bindingsメタデータを元に EJB ホームとリモートインターフェースプロキシを管理するEJBProxyFactory(org.jboss.ejb.EJBProxyFactory) を作成します。EJB には複数のプロキシファクトリを関連付けることができ、これから、この定義方法について見ていきます。ProxyFactoryは論理プロキシを構築し、ホームを JNDI にバインドします。論理プロキシは、動的なProxy(java.lang.reflect.Proxy)、プロキシが公開する EJB のホームインターフェース、ClientContainer(org.jboss.proxy.ClientContainer) 形式のProxyHandler(java.lang.reflect.InvocationHandler) 実装、クライアント側のインターセプターで構成されています。EJBProxyFactoryで作成したプロキシは、標準のダイナミックプロキシです。EJBModuleメタデータで定義されているように、EJB ホームとリモートインターフェースをプロキシ化するシリアル可能なオブジェクトです。プロキシは、このプロキシに関連付けられたClientContainerハンドラーを使って、強く型付けされた EJB インターフェースで出されたリクエストを型付けされていない呼び出しに変換します。これは、クライアントをルックアップする EJB ホームインターフェースとして JNDI にバインドされた動的プロキシインスタンスです。クライアントが EJB ホームをルックアップすると、ホームプロキシはClientContainerとそのインターセプターとともに、クライアント VM へ移植されます。動的なプロキシを使うと、他の多くのEJB コンテナーでは必要となる EJB 固有の編集手順を行わなくてもよくなります。- EJB ホームインターフェースは、ejb-jar.xml 記述子で宣言し、EJBModule メタデータから利用可能です。動的プロキシの主なプロパティは、これらのプロキシを公開するインターフェースを実装するために表示されます。これは、Java の強く型付けされたシステムにおいては当てはまります。プロキシは、ホームインターフェースのどれにでもキャスティングでき、またプロキシ化するインターフェースの全詳細を提供するプロキシを反映することができます。
- プロキシは、
ClientContainerハンドラーへのインターフェースのいずれかを使った呼び出しを委譲します。ハンドラーで必要とされる唯一のメソッドは、public Object invoke(Object proxy, Method m, Object[] args) throws Throwableです。EJBProxyFactoryは、ClientContainerを作成し、これをProxyHandlerとして割り当てます。ClientContainerのステータスには、InvocationContext(org.jboss.invocation.InvocationContext)とインターセプターのチェーン (org.jboss.proxy.Interceptor) が含まれています。InvocationContextは以下を含みます。Proxyが関連付けられている EJB コンテナー MBean の JMXObjectName- EJB 向けの
javax.ejb.EJBMetaData - EJB ホームインターフェースの JNDI 名
- トランスポート固有の呼び出し (
org.jboss.invocation.Invoker)
インターセプターチェーンは、EJB ホームとリモートインターフェースの動作を組み立てる機能ユニットで構成されています。これは、jboss.xml記述子についての説明時に見ていきますが、EJB の設定可能なアスペクトで、インターセプターのマークアップがEJBModuleメタデータに含まれています。インターセプター (org.jboss.proxy.Interceptor) は、様々な EJB タイプ、セキュリティ、トランザクション、トランスポートを処理します。独自のインターセプターの追加も可能です。 - プロキシに関連付けられたトランスポート固有の呼び出しは、EJB メソッド呼び出しのトランスポート詳細を処理するサーバー側の分離呼び出しへ紐付けされています。分離呼び出しは、JBoss サーバー側のコンポーネントです。
クライアント側のインターセプターの設定は
jboss.xmlclient-interceptors を使って行います。ClientContainer 呼び出しメソッドが呼び出されると、型なしの Invocation (org.jboss.invocation.Invocation) を作成しリクエストをカプセル化します。これがインターセプターチェーンに渡されます。チェーンの最後のインターセプターがトランスポートハンドラーとなり、サーバーへリクエストを送信し、返信を取得する方法を把握しており、トランスポート固有の内容に対応します。
クライアントのインターセプター設定の利用例にあるように、
server/production/standardjboss.xml のデフォルトのステートレスセッション bean 設定を見てみましょう。例29.1「Standard Stateless SessionBean 設定からのクライアントインターセプター」 は、 Standard Stateless SessionBean が参照する stateless-rmi-invoker クライアントのインターセプター設定について示しています。
例29.1 Standard Stateless SessionBean 設定からのクライアントインターセプター
<invoker-proxy-binding>
<name>stateless-rmi-invoker</name>
<invoker-mbean>jboss:service=invoker,type=jrmp</invoker-mbean>
<proxy-factory>org.jboss.proxy.ejb.ProxyFactory</proxy-factory>
<proxy-factory-config>
<client-interceptors>
<home>
<interceptor>org.jboss.proxy.ejb.HomeInterceptor</interceptor>
<interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
<interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
<interceptor call-by-value="false">
org.jboss.invocation.InvokerInterceptor
</interceptor>
<interceptor call-by-value="true">
org.jboss.invocation.MarshallingInvokerInterceptor
</interceptor>
</home>
<bean>
<interceptor>org.jboss.proxy.ejb.StatelessSessionInterceptor</interceptor>
<interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
<interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
<interceptor call-by-value="false">
org.jboss.invocation.InvokerInterceptor
</interceptor>
<interceptor call-by-value="true">
org.jboss.invocation.MarshallingInvokerInterceptor
</interceptor>
</bean>
</client-interceptors>
</proxy-factory-config>
</invoker-proxy-binding>
<container-configuration>
<container-name>Standard Stateless SessionBean</container-name>
<call-logging>false</call-logging>
<invoker-proxy-binding-name>stateless-rmi-invoker</invoker-proxy-binding-name>
<!-- ... -->
</container-configuration>
これは、ステートレス bean の設定をオーバーライドする EJB JAR
META-INF/jboss.xml がない場合に利用される、ステートレスセッション bean 向けのクライアントインターセプター設定です。各クライアントインターセプターが提供する機能は以下の通りです。
- org.jboss.proxy.ejb.HomeInterceptor:
getHomeHandle、getEJBMetaDataを処理し、クライアント VM 内でローカルにてEJBHomeインターフェースのメソッドを削除します。その他のメソッドは、次のインターセプターに伝搬されます。 - org.jboss.proxy.ejb.StatelessSessionInterceptor: クライアント VM 内でローカルにて
EJBObjectインターフェースのtoString、equals、hashCode、getHandle、getEJBHome、isIdenticalメソッドを処理します。その他のメソッドは、次のインターセプターに伝搬されます。 - org.jboss.proxy.SecurityInterceptor: 現在のセキュリティコンテキストをメソッド呼び出しと関連付け、他のインターセプターやサーバーで利用できるようにします。
- org.jboss.proxy.TransactionInterceptor: アクティブなトランザクションと呼び出しメソッドの呼び出しを関連付け、他のインターセプターが利用できるようにします。
- org.jboss.invocation.InvokerInterceptor: メソッド呼び出しのディスパッチをトランスポート固有の呼び出しにカプセル化します。クライアントがサーバーと同じ VM で実行しているか、またこのような場合はオプションで参照渡しへの呼び出しをルーティングするか把握しています。クライアントがサーバー VM の外にある場合、このインターセプターは、この呼び出しを呼び出しコンテキストが紐付いたトランスポート呼び出しに委譲します。例29.1「Standard Stateless SessionBean 設定からのクライアントインターセプター」 設定の場合、これは、
jboss:service=invoker,type=jrmp(JRMPInvokerサービス)が紐付いている呼び出しスタブとなります。org.jboss.invocation.MarshallingInvokerInterceptor: VM 内の呼び出しを最適化しないようにInvokerInterceptorを継承します。これを使いメソッド呼び出しにcall-by-valueセマンティクスを強制的に利用させます。
29.1.1. EJB プロキシ設定の指定
EJB 呼び出しトランスポートとクライアントのプロキシインターセプタースタックを指定するには、EJB JAR
META-INF/jboss.xml 記述子あるいはサーバーのstandardjboss.xml 記述子のいずれかにある invoker-proxy-binding を定義する必要があります。各種デフォルトの EJB コンテナー設定や標準の RMI/JRMP や RMI/IIOP トランスポートプロトコル向けにstandardjboss.xml 記述子に定義されているデフォルトの invoker-proxy-bindings が複数あります。現在のデフォルトプロキシ設定は以下のとおりです。
- entity-rmi-invoker: エンティティ bean 向けの RMI/JRMP 設定
- clustered-entity-rmi-invoker: クラスター化されたエンティティ bean 向けの RMI/JRMP 設定
- stateless-rmi-invoker: ステートレスセッション bean 向けの RMI/JRMP 設定
- clustered-stateless-rmi-invoker: クラスター化されたステートレスセッション bean 向けの RMI/JRMP 設定
- stateful-rmi-invoker: クラスター化されたステートフルセッション bean 向けの RMI/JRMP 設定
- clustered-stateful-rmi-invoker: クラスター化されたステートフルセッション bean 向けの RMI/JRMP 設定
- message-driven-bean: メッセージ駆動型 bean 向けの JMS 呼び出し
- singleton-message-driven-bean: シングルトンメッセージ駆動型 bean 向けの JMS 呼び出し
- message-inflow-driven-bean: メッセージインフロー駆動型 bean の JMS 呼び出し
- jms-message-inflow-driven-bean: 標準のメッセージ駆動型 bean 向けの JMS インフロー呼び出し
- iiop: セッション bean およびエンティティ bean と共に利用する RMI/IIOP
新規のプロトコルバインディングを導入し、プロキシファクトリあるいはクライアント側のインターセプタースタックをカスタマイズするには、新たに
invoker-proxy-bindingを定義する必要がります。プロキシ設定を指定する際の完全な invoker-proxy-binding DTD 部分については、図29.2「invoker-proxy-binding スキーマ」 にあります。

図29.2 invoker-proxy-binding スキーマ
invoker-proxy-binding の子要素は以下の通りです。
- name:
name要素は、invoker-proxy-bindingの一意名を渡します。追加のプロキシバインディングを指定するためにデフォルトのプロキシバインディングと EJB デプロイメントレベルが設定されている場合は、この名前を使い、EJB コンテナー設定からのバインディングを参照します。サーバー側の EJB コンテナー設定を制御するjboss.xml要素をみていただくとこれがどのように行われているかがわかります。 - invoker-mbean:
invoker-mbean要素は、プロキシ呼び出しが紐付けられる分離呼び出し MBean サービスの JMXObjectName文字列を渡します。 - proxy-factory:
proxy-factory要素は、org.jboss.ejb.EJBProxyFactoryインターフェースを実装する必要のあるプロキシファクトリの完全修飾クラス名を指定します。EJBProxyFactoryは、プロキシの設定、プロトコル固有の呼び出し、コンテキストの関連付けといった処理を行います。EJBProxyFactoryインターフェースの現在の JBoss 実装は以下を含みます。- org.jboss.proxy.ejb.ProxyFactory: RMI/JRMP 固有のファクトリ
- org.jboss.proxy.ejb.ProxyFactoryHA: クラスター RMI/JRMP 固有のファクトリ
- org.jboss.ejb.plugins.jms.JMSContainerInvoker: JMS 固有のファクトリ
- org.jboss.proxy.ejb.IORFactory: RMI/IIOP 固有のファクトリ
- proxy-factory-config:
proxy-factory-config要素は、proxy-factory実装の追加情報を指定します。残念ながら、各種要素は構造化されていません。プロキシファクトリの各型を適用しているのは、一部の要素のみとなっています。子要素は、3つの呼び出しプロトコル (RMI/RJMP、RMI/IIOP、JMS) に分類されます。
RMI/JRMP 固有のプロキシファクトリ、
org.jboss.proxy.ejb.ProxyFactory、org.jboss.proxy.ejb.ProxyFactoryHA については、以下の要素を適用します。
- client-interceptors:
client-interceptorsは、ホームとリモートを定義します。また、オプションで複数の値を持つプロキシインターセプタースタックも定義します。 - web-class-loader: 動的なクラスローディングができるように、web クラスローダーは、プロキシに関連付けられるべき
org.jboss.web.WebClassLoaderインスタンスを定義します。
以下の
proxy-factory-config は、RMI でアクセスしたエンティティ bean 用です。
<proxy-factory-config>
<client-interceptors>
<home>
<interceptor>org.jboss.proxy.ejb.HomeInterceptor</interceptor>
<interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
<interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
<interceptor call-by-value="false">
org.jboss.invocation.InvokerInterceptor
</interceptor>
<interceptor call-by-value="true">
org.jboss.invocation.MarshallingInvokerInterceptor
</interceptor>
</home>
<bean>
<interceptor>org.jboss.proxy.ejb.EntityInterceptor</interceptor>
<interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
<interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
<interceptor call-by-value="false">
org.jboss.invocation.InvokerInterceptor
</interceptor>
<interceptor call-by-value="true">
org.jboss.invocation.MarshallingInvokerInterceptor
</interceptor>
</bean>
<list-entity>
<interceptor>org.jboss.proxy.ejb.ListEntityInterceptor</interceptor>
<interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
<interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
<interceptor call-by-value="false">
org.jboss.invocation.InvokerInterceptor
</interceptor>
<interceptor call-by-value="true">
org.jboss.invocation.MarshallingInvokerInterceptor
</interceptor>
</list-entity>
</client-interceptors>
</proxy-factory-config>
RMI/IIOP 固有のプロキシファクトリ
org.jboss.proxy.ejb.IORFactoryについては、以下の要素を適用します。
- web-class-loader: 動的なクラスローディングができるように、web クラスローダーは、プロキシに関連付けられるべき
org.jboss.web.WebClassLoaderインスタンスを定義します。 - poa: 移植可能なオブジェクトアダプターの用途。有効な値は、
per-servantとsharedとなっています。 - register-ejbs-in-jnp-context: EJB が JNDI で登録されるべきか指定するフラグ
- jnp-context: EJB を登録する JNDI コンテキスト
- interface-repository-supported: これは、デプロイ済みの EJB が独自の CORBA インターフェースレポジトリを持つか否かを指定します。
以下は、IIOP でアクセスした EJB の
proxy-factory-config です。
<proxy-factory-config>
<web-class-loader>org.jboss.iiop.WebCL</web-class-loader>
<poa>per-servant</poa>
<register-ejbs-in-jnp-context>true</register-ejbs-in-jnp-context>
<jnp-context>iiop</jnp-context>
</proxy-factory-config>
JMS 固有のプロキシファクトリ、
org.jboss.ejb.plugins.jms.JMSContainerInvoker については、以下の要素を適用します。
- MinimumSize: これは、MDB 処理の最小プールサイズを指定します。デフォルト値は 1 です。
- MaximumSize: これは、JMS のデスティネーションで許容できる同時 MDB 数の上限を指定します。デフォルト値は、15 です。
- MaxMessages: これは、
javax.jms.QueueConnectionとjavax.jms.TopicConnectionインターフェースのcreateConnectionConsumerメソッドに対するmaxMessagesパラメーター値だけでなく、javax.jms.TopicConnectionのcreateDurableConnectionConsumerメソッドに対するmaxMessagesパラメーター値を指定します。これは1度のサーバーセッションに割り当て可能な最大メッセージ数です。この値は、JMS プロバイダーが対応していると表明していない場合は、デフォルト値から変更すべきではありません。 - KeepAliveMillis: これは、セッションプール内のセッション間のキープアライブ間隔をミリ秒単位で指定します。デフォルト値は、30000 (30 秒) です。
- MDBConfig: MDB JMS 接続動作の設定。要素野中で対応しているものは、以下のとおりです。
- ReconnectIntervalSec: JMS サーバーへの接続回復を試行するまでの待機時間 (秒単位)
- DeliveryActive: MDB が起動時に有効かどうか。デフォルトは True となっています。
- DLQConfig: MDB のデッドレターキューの設定。メッセージの再送が多すぎる場合に利用されます。
- JMSProviderAdapterJNDI:
java:/名前空間の JMS プロバイダーアダプターの JNDI 名。これは、MDB には必須で、org.jboss.jms.jndi.JMSProviderAdapterを実装する必要があります。 - ServerSessionPoolFactoryJNDI: JMS プロバイダーのセッションプールファクトリの
java:/名前空間にあるセッションプールの JNDI 名。これは MDB には必須で、org.jboss.jms.asf.ServerSessionPoolFactoryを実装する必要があります。
例29.2「JMSContainerInvoker proxy-factory-config 例」 では、
standardjboss.xml 記述子から抜粋した、サンプルの proxy-factory-config を提示しています。
例29.2 JMSContainerInvoker proxy-factory-config 例
<proxy-factory-config>
<JMSProviderAdapterJNDI>DefaultJMSProvider</JMSProviderAdapterJNDI>
<ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI>
<MinimumSize>1</MinimumSize>
<MaximumSize>15</MaximumSize>
<KeepAliveMillis>30000</KeepAliveMillis>
<MaxMessages>1</MaxMessages>
<MDBConfig>
<ReconnectIntervalSec>10</ReconnectIntervalSec>
<DLQConfig>
<DestinationQueue>queue/DLQ</DestinationQueue>
<MaxTimesRedelivered>10</MaxTimesRedelivered>
<TimeToLive>0</TimeToLive>
</DLQConfig>
</MDBConfig>
</proxy-factory-config>