JavaベースのWebアプリケーションアーキテクチャを共有しましょう!
Javaを使用して実装されるWebアプリケーションには、さまざまなアーキテクチャが数多くあります。この質問への回答は、さまざまなWebアプリケーション設計のライブラリとして役立ち、長所と短所があります。答えは主観的なものになると思いますが、できる限り客観的になるようにして、リストする長所と短所に動機を与えましょう。
アーキテクチャの説明に使用する詳細レベルを使用してください。答えが価値のあるものになるためには、少なくとも、あなたが説明するアーキテクチャで使用される主要なテクノロジーとアイデアを説明する必要があります。そして最後に重要なことですが、いつあなたのアーキテクチャを使うべきですか?
始めます...
アーキテクチャの概要
Java EE、Java Persistence API、サーブレット、Javaサーバーページなど、Sunのオープンスタンダードに基づく3層アーキテクチャを使用しています。
- 持続性
- ビジネス
- プレゼンテーション
レイヤー間の可能な通信フローは次のように表されます。
Persistence <-> Business <-> Presentation
たとえば、プレゼンテーション層が永続化操作を呼び出したり実行したりすることはなく、常にビジネス層を通じて実行されます。このアーキテクチャは、高可用性Webアプリケーションの要求を満たすことを目的としています。
持続性
作成、読み取り、更新、削除(CRUD)の永続化操作を実行します。今回のケースでは(Java Persistence API)JPAを使用しており、現在、Hibernateを永続性プロバイダーとして使用し、そのEntityManagerを使用しています。
このレイヤーは複数のクラスに分割され、各クラスは特定のタイプのエンティティ(つまり、ショッピングカートに関連するエンティティが単一の永続クラスによって処理される場合があります)を扱い、1人のマネージャーだけが使用します。
また、この層はまた、格納JPAエンティティのようなものですAccount
、ShoppingCart
など
ビジネス
Webアプリケーション機能に関連付けられているすべてのロジックは、このレイヤーにあります。この機能は、自分のクレジットカードを使用してオンラインで製品の支払いを希望する顧客の送金を開始する場合があります。新しいユーザーを作成したり、ユーザーを削除したり、Webベースのゲームでの戦闘の結果を計算したりすることもできます。
この層は、複数のクラスに分割され、これらのクラスの各々を用いて注釈さ@Stateless
になるようにステートレスセッションBean(SLSB)。各SLSBはマネージャーと呼ばれ、たとえば、マネージャーはと呼ばれるように注釈が付けられたクラスである場合がありますAccountManager
。
AccountManager
CRUD操作を実行する必要がある場合AccountManagerPersistence
、永続化レイヤーのクラスであるのインスタンスを適切に呼び出します。の2つの方法の概略AccountManager
は次のようになります。
...
public void makeExpiredAccountsInactive() {
AccountManagerPersistence amp = new AccountManagerPersistence(...)
// Calls persistence layer
List<Account> expiredAccounts = amp.getAllExpiredAccounts();
for(Account account : expiredAccounts) {
this.makeAccountInactive(account)
}
}
public void makeAccountInactive(Account account) {
AccountManagerPersistence amp = new AccountManagerPersistence(...)
account.deactivate();
amp.storeUpdatedAccount(account); // Calls persistence layer
}
コンテナーマネージャートランザクションを使用するため、自分自身のトランザクション境界設定を行う必要はありません。基本的に内部では、SLSBメソッドに入るときにトランザクションを開始し、メソッドを終了する直前にコミット(またはロールバック)します。これは構成に関する規約の例ですが、デフォルトであるRequired以外はまだ必要ありません。
SunのJava EE 5チュートリアルで、Enterprise JavaBeans(EJB)に必要なトランザクション属性について説明しています。
クライアントがトランザクション内で実行され、エンタープライズBeanのメソッドを呼び出す場合、メソッドはクライアントのトランザクション内で実行されます。クライアントがトランザクションに関連付けられていない場合、コンテナはメソッドを実行する前に新しいトランザクションを開始します。
必須属性は、コンテナ管理のトランザクション境界で実行されるすべてのエンタープライズBeanメソッドの暗黙的なトランザクション属性です。別のトランザクション属性をオーバーライドする必要がない限り、通常はRequired属性を設定しません。トランザクション属性は宣言型であるため、後で簡単に変更できます。
プレゼンテーション
私たちのプレゼンテーション層は...プレゼンテーションを担当しています!これはユーザーインターフェイスを担当し、HTMLページを作成し、GETおよびPOSTリクエストを通じてユーザー入力を受信することにより、ユーザーに情報を表示します。現在、古いServletと Java Server Pages(JSP)の組み合わせを使用しています。
レイヤーは、ビジネスレイヤーのマネージャーのメソッドを呼び出して、ユーザーが要求した操作を実行し、Webページに表示する情報を受け取ります。ビジネス層から受け取った情報は、String
やint
egers ほど複雑ではないタイプの場合もあれば、JPAエンティティーの場合もあります。
アーキテクチャの長所と短所
長所
- この層で永続化を行う特定の方法に関連するすべてのものがあるということは、ビジネス層で何かを書き直す必要なしに、JPAの使用から別のものへの交換ができることだけを意味します。
- プレゼンテーションレイヤーを別のレイヤーに交換するのは簡単です。より良いものが見つかれば、そうなる可能性があります。
- EJBコンテナにトランザクション境界を管理させるのは素晴らしいことです。
- サーブレットの+ JPAの使用は簡単で(そもそも)、テクノロジは広く使用され、多くのサーバーに実装されています。
- Java EEを使用すると、負荷分散とフェイルオーバーを備えた高可用性システムを簡単に作成できるようになります。どちらも必要だと感じています。
短所
- JPAを使用する
@NamedQuery
と、JPAエンティティクラスのアノテーションを使用して、よく使用するクエリを名前付きクエリとして保存できます。私たちのアーキテクチャーのように、永続性クラスで永続性に関連するものをできるだけ多く持っている場合、これにより、JPAエンティティーを含めるためのクエリが見つかる可能性のある場所も広がります。永続化操作の概要を把握することが難しくなり、維持することが難しくなります。 - 永続化レイヤーの一部としてJPAエンティティーがあります。しかし
Account
、そしてShoppingCart
、彼らは本当にビジネスオブジェクトではありませんか?これらのクラスに触れて、JPAが処理方法を知っているエンティティーに変換する必要があるため、この方法で行われます。 - ビジネスオブジェクトでもあるJPAエンティティは、値オブジェクト(VO)としても知られるデータ転送オブジェクト(DTO)のように作成されます。ビジネスオブジェクトにはアクセサメソッドを除いて独自のロジックがないため、これは貧血ドメインモデルになります。すべてのロジックは、ビジネスレイヤーのマネージャーによって行われるため、より手続き型のプログラミングスタイルになります。それは良いオブジェクト指向のデザインではありませんが、多分それは問題ではありませんか?(結局のところ、オブジェクト指向は、結果をもたらしたプログラミングパラダイムだけではありません。)
- EJBとJava EEを使用すると、少し複雑になります。また、純粋にTomcatを使用することはできません(EJBマイクロコンテナーの追加は、純粋に Tomcatではありません)。
- サーブレットとJPAの使用には多くの問題があります。これらの問題の詳細については、Googleを使用してください。
- ビジネスレイヤーを終了するとトランザクションが閉じられるため
fetch=FetchType.LAZY
、プレゼンテーションレイヤー内から(を使用して)必要なときにデータベースからロードするように構成されているJPAエンティティから情報をロードすることはできません。例外が発生します。これらの種類のフィールドを含むエンティティを返す前に、関連するゲッターを呼び出す必要があります。別のオプションは、Java Persistence Query Language(JPQL)を使用して行うことFETCH JOIN
です。ただし、これらのオプションはどちらも少し面倒です。