WildFlyアプリケーションサーバーでのEJB JNDIルックアップの概要
1. 概要
Enterprise Java Beans(EJB)は、分散エンタープライズレベルアプリケーションの開発を簡素化することを目的としたJava EE specificationのコア部分です。 EJBのライフサイクルは、JBoss WildFlyやOracle GlassFishなどのアプリケーションサーバーによって処理されます。
EJBは、トランザクション処理、コンポーネントライフサイクル管理、依存性注入などの非ビジネスロジック関連の問題を処理するアプリケーションサーバー次第であるため、エンタープライズレベルのソフトウェアモジュールの実装を容易にする堅牢なプログラミングモデルを提供します。
このチュートリアルでは、WildFlyに基本的なEJBモジュールを実装し、リモートクライアントからJNDIを介してEJBを呼び出す方法を示します。
2. EJBモジュールの実装
ビジネスロジックは、1つまたは複数のローカル/リモートビジネスインターフェイス(ローカル/リモートビューとも呼ばれる)によって実装されるか、インターフェイスを実装しないクラス(非ビューインターフェイス)から直接実装されます。
同じ環境に存在するクライアントからBeanにアクセスする場合、つまり、ローカルビジネスインターフェイスが使用されることに注意してください。 同じEARまたはWARファイル。ただし、異なる環境からBeanにアクセスする場合は、リモートビジネスインターフェースが必要です。 別のJVMまたはアプリケーションサーバー。
1つのBeanだけで構成される基本的なEJBモジュールを作成しましょう。 Beanのビジネスロジックは単純で、特定のStringを大文字バージョンに変換することに限定されます。
2.1. リモートビジネスインターフェイスの定義
まず、@Remoteアノテーションで装飾された単一のリモートビジネスインターフェイスを定義しましょう。 EJB 3.x specificationによると、Beanはリモートクライアントからアクセスされるため、これは必須です。
@Remote
public interface TextProcessorRemote {
String processText(String text);
}
2.2. ステートレスBeanの定義
次に、前述のリモートインターフェイスを実装してビジネスロジックを実現しましょう。
@Stateless
public class TextProcessorBean implements TextProcessorRemote {
public String processText(String text) {
return text.toUpperCase();
}
}
TextProcessorBeanクラスは、@Statelessアノテーションで装飾された単純なJavaクラスです。
ステートレスBeanは、定義上、クライアントがさまざまなリクエスト間でインスタンスの状態を維持できる場合でも、クライアントとの会話状態を維持しません。 対応するステートフルBeanは、会話状態を保持します。たとえば、アプリケーションサーバー用に作成するのに費用がかかります。
この場合、上記のクラスにはインスタンス状態がないため、ステートレスにすることができます。 状態がある場合、異なるクライアント要求でそれを使用してもまったく意味がありません。
Beanの動作は決定論的です。つまり、適切に設計されたBeanのように、副作用はありません。入力Stringを受け取り、その大文字バージョンを返すだけです。
2.3. Mavenの依存関係
次に、javaee-api Mavenアーティファクトをモジュールに追加する必要があります。これにより、EJBに必要なものを含むすべてのJava EE7仕様APIが提供されます。
javax
javaee-api
7.0
provided
この時点で、基本的かつ機能的なEJBモジュールを作成することができました。 すべての潜在的なクライアントが使用できるようにするには、アーティファクトをローカルMavenリポジトリにJARファイルとして追加する必要があります。
2.4. ローカルリポジトリへのEJBモジュールのインストール
これを達成するためのいくつかの方法があります。 最も簡単な方法は、Mavenライフサイクルclean – installのビルドフェーズを実行することです。
mvn clean install
このコマンドは、EJBモジュールをejbmodule-1.0.jar (またはpom.xmlファイルで指定された任意のアーティファクトIDとしてローカルリポジトリにインストールします。 Mavenを使用してローカルJARをインストールする方法の詳細については、this articleを確認してください。
EJBモジュールがローカルリポジトリに正しくインストールされていると仮定すると、次のステップは、TextProcessorBeanAPIを利用するリモートクライアントアプリケーションを開発することです。
3. リモートEJBクライアント
リモートEJBクライアントのビジネスロジックを非常にシンプルに保ちます。最初に、JNDIルックアップを実行してTextProcessorBeanプロキシを取得します。 その後、プロキシのprocessText()メソッドを呼び出します。
3.1. Mavenの依存関係
EJBクライアントが期待どおりに動作するには、次のMavenアーティファクトを含める必要があります。
javax
javaee-api
7.0
provided
org.wildfly
wildfly-ejb-client-bom
10.1.0.Final
com.beldung.ejbmodule
ejbmodule
1.0
javaee-apiアーティファクトを含める理由は明らかですが、wildfly-ejb-client-bomを含めることはできません。 The artifact is required for performing remote EJB invocations on WildFly.
大事なことを言い忘れましたが、以前のEJBモジュールをクライアントが利用できるようにする必要があるため、ejbmodule依存関係も追加しました。
3.2. EJBクライアントクラス
EJBクライアントがTextProcessorBeanのプロキシを呼び出すことを考えると、非常に実用的であり、クライアントクラスにTextApplicationという名前を付けます。
public class TextApplication {
public static void main(String[] args) throws NamingException {
TextProcessorRemote textProcessor = EJBFactory
.createTextProcessorBeanFromJNDI("ejb:");
System.out.print(textProcessor.processText("sample text"));
}
private static class EJBFactory {
private static TextProcessorRemote createTextProcessorBeanFromJNDI
(String namespace) throws NamingException {
return lookupTextProcessorBean(namespace);
}
private static TextProcessorRemote lookupTextProcessorBean
(String namespace) throws NamingException {
Context ctx = createInitialContext();
String appName = "";
String moduleName = "EJBModule";
String distinctName = "";
String beanName = TextProcessorBean.class.getSimpleName();
String viewClassName = TextProcessorRemote.class.getName();
return (TextProcessorRemote) ctx.lookup(namespace
+ appName + "/" + moduleName
+ "/" + distinctName + "/" + beanName + "!" + viewClassName);
}
private static Context createInitialContext() throws NamingException {
Properties jndiProperties = new Properties();
jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jboss.naming.remote.client.InitialContextFactory");
jndiProperties.put(Context.URL_PKG_PREFIXES,
"org.jboss.ejb.client.naming");
jndiProperties.put(Context.PROVIDER_URL,
"http-remoting://localhost:8080");
jndiProperties.put("jboss.naming.client.ejb.context", true);
return new InitialContext(jndiProperties);
}
}
}
簡単に言えば、TextApplication __クラスが行うことは、Beanプロキシを取得し、サンプル文字列を使用してそのprocessText()メソッドを呼び出すことだけです。
実際のルックアップは、ネストされたクラスEJBFactoryによって実行されます。このクラスは、最初にJNDIInitialContextインスタンスを作成し、次に必要なJNDIパラメーターをコンストラクターに渡し、最後にそれを使用してBeanプロキシーをルックアップします。
ルックアップは、WildFly独自の「ejb:」名前空間を使用して実行されることに注意してください。 これにより、プロキシが明示的に呼び出されるまでクライアントがサーバーへの接続を延期するため、ルックアッププロセスが最適化されます。
「ejb」名前空間にまったく頼らずにBeanプロキシを検索できることも注目に値します。 ただし、we’d be missing all the additional benefits of lazy network connections, thus making the client a lot less performant。
3.3. EJBコンテキストの設定
クライアントは、Beanルックアップを実行するために接続を確立するホストとポートを知っている必要があります。 この点で、the client requires setting up the proprietary WildFly EJB context, which is defined with the jboss-ejb-client.properties fileはクラスパスに配置され、通常はsrc/main/resourcesフォルダーの下に配置されます。
endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=127.0.0.1
remote.connection.default.port=8080
remote.connection.default.connect.options.org.xnio.Options
.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.username=myusername
remote.connection.default.password=mypassword
このファイルは、リモート接続のデフォルト数、デフォルトのホストとポート、ユーザー資格情報など、WildFlyへの接続を確立するために必要なすべてのパラメーターを提供するため、一目瞭然です。 この場合、接続は暗号化されませんが、SSLが有効になっている場合は接続できます。
考慮すべき最後のことは、if the connection requires authentication, it’s necessary to add a user to WildFly via the https://docs.jboss.org/author/display/WFLY8/add-user+utility?sscc=t[_add-user.sh/add-user.bat utility].