まとめこの記事では、注釈と側面の力を組み合わせて、コンテナの独立性を提供しながら、EJB 3.0と互換性のある方法で企業に宣言的サービスを提供する方法について説明します。
1。はじめに
ソフトウェア開発の生産パフォーマンスをさらに向上させる方法の共同追求において、私たちはJavaコミュニティのメンバーとして、一般的にJ2EEに頼り、分散トランザクション管理、並行性、オブジェクト配信ソリューションなどのエンタープライズ開発においてより挑戦的な技術的問題を提供します。その背後にある指針となるイデオロギー - これらの複雑なエンタープライズサービスは、アプリケーションサーバーベンダーによって実装され、商業開発者によってバランスが取れていることが確かに良い考えです。 J2EE、特にEJBは、エンタープライズJavaアプリケーションが構築されるプラットフォームを正常に提供しました。
この成功の一部は、宣言的なプログラミングを実行する能力(プログラムを開発する方法)が原因で、コードがどこにでも広がるように、ビジネスロジックで明示的にエンコードされる代わりにインフラストラクチャサービスを宣言できます。 EJBは、このプログラミングアプローチの価値を証明しています - トランザクションやセキュリティなどの企業の問題を公開記述子で宣言し、コンテナで処理することにより。
しかし、過去数年間、ますます多くの開発者が、EJBがチームの生産性に多くの新たな課題をもたらしていることに気付きました。各EJBには、JNDIを介してアクセスされる公開記述子の説明を備えた複数のインターフェイスを添付する必要があります。コンテナの外側のEJBでのユニットテストも、純粋なオブジェクト指向の開発に焦点を当てていないため、追加の困難をもたらします。
この記事を読むには、次のツールが必要であることに注意してください。
・Java 2 SDK 1.5
・Maven 2.0ベータ2
EJB 3.0の目標は、次の面でエンタープライズ開発を容易にすることです。
・メタデータアノテーションを導入することにより、エンタープライズサービスの宣言要求を実装する
・注釈を介して依存関係/リソースインジェクションを実装します
・エンタープライズビーンズとEJB固有のインターフェイスのデカップリングを実装する
・軽量オブジェクトリレーショナルマッピングによる連続ストレージの簡素化
これは、EJB開発者にとって春のそよ風のようなものです。彼らはEJBの開発、テスト、維持のために一生懸命働いてきました。 EJB 3.0を使用してエンタープライズビーンを作成するのは簡単です。これは、特定の注釈を備えたPojo(従来のJavaオブジェクト)を作成して、EJBとしてマークし、エンタープライズサービスを要求します。 EJB 3.0パブリックドラフトのEJBの例を次に示します。
@stateful
パブリッククラスのカートビーンはショッピングカートを実装します
{
プライベートフロート合計;
プライベートベクトル製品コード。
public int someshoppingmethod(){...};
...
}
EJB 3.0ステートメントは、開発者が必要とするものはヘビー級ではなく、軽量で使いやすいソリューションであると述べています。この目的のために、EJB 3.0で提供される最も重要な方法の1つは、エンタープライズビーンズとEJB APIを切り離すことです。また、このソリューションは興味深い派生物ももたらします - EJBはさまざまなEJBコンテナだけでなく、アプリケーションフレームワーク内でも実行できるようになりました。これらのフレームワークは、EJB 3.0(JSR 220)と宣言するエンタープライズサービスの通常の注釈を認識できる必要があります(JSR 250) 。
この記事では、宣言的なプログラミング、EJB、アスペクト、または注釈の詳細な調査は提供されていません。代わりに、これらのテクノロジー間の相互関係を分析し、それらを新しい方法で組み合わせてアプリケーション開発を簡素化する方法について説明します。
この記事では、EJB 3.0の互換性のある豆の書き込み方法を学び、いくつかの簡単な側面を作成して、宣言的なトランザクション管理、セキュリティ、およびリソースインジェクションを作成します。私はあなたがこの演習から利益を得ることができることを願っています:
・学習における3つの実用的なアプリケーション(依存関係注入、セキュリティ、およびトランザクション)。
・EJB 3.0とその背後にあるアイデアに精通しています。
特定のAPIからEJBのデカップリングを実装する方法を認識して、EJB 3.0互換サービスをEJBのみで提供するのではなく、軽量で実装できるようにします。
2。アプリケーション飛行順序の例
議論を通して、あなたは側面と注釈を使用して依存関係の注入、セキュリティ、およびトランザクション管理を実装する、飛行順序付けシステムの実装について学びます。アプリは2つの機能のみを実行します。ユーザーがフライトを検索し(図1)、旅行を注文することができます(図2)。両方の操作は、識別されたユーザーのみがそれらを実行できるように安全に処理されます。さらに、「注文旅行」操作には2つのフライト(アウトフライトと帰りのフライト)の注文が含まれるため、操作をトランザクションとして作成する必要があります。たとえば、両方の注文は成功または作業単位として失敗します。
図1。フライトクエリ:最初に、ユーザーは指定された基準を満たすフライトを探します。
図2。フライトの順序:次に、ユーザーはアウトバウンドフライトとリターンフライトを注文します。両方の注文は成功または失敗します。
このシンプルなWebアプリケーションには、いくつかのサーブレット、サービスの外観、DAO層が含まれています(図3を参照)。
リソース構成、セキュリティ、トランザクション管理などの相互懸念は、Java 5注釈で宣言されたインジェクション挙動を実装するために、アスペクト(AspectJ 1.5 m3で実装)によって提供されます。
図3。フライト順序システムアーキテクチャ:このフライト順序システムは、3つの主要なコンポーネントで構成されています。これらは、ユーザーリクエストを完了するために一緒になります。 3。リソースインジェクション
EJB 3.0ドラフト宣言により、@Resourceアノテーション(この決定は通常の注釈宣言ドラフトで定義されている)を介してリソースを宣言し、コンテナでEJBに注入します。依存関係の注入は手法です - この手法を使用して、オブジェクトのために明示的に作成されたエンティティではなく、オブジェクトの外側のエンティティを使用することで、オブジェクトの依存性を提供(注入)できます。それは時々ハリウッドの原則として説明されています - 「私たちを呼んではいけない、私たちはあなたを呼ぶ」のような冗談を言っています。
TravelagencyServiceImplクラスを例として実行します - データを継続的に保存するために、このクラスはiflightdaoインターフェイスの実装を見つける必要があります。従来、これは工場、シングルトン、サービスロケーター、またはその他のカスタマイズされたソリューションを介して実現されています。その中で、考えられる解決策の1つは次のようになります。
Public Class TravelAgencyServiceImpl IttravelagencyServiceを実装します
{
Public Iflightdao Flightdao;
public TravelAgencyServiceImpl()
{FlightDao = FlightDaofactory.getInstance()。
Public void Booktrip(長いアウトバウンドflightid、long returnflightid、intシート)
InvalidSeatsexceptionをスローします
{
ReserveSeats(outboundflightid、座席);
ReserveSeats(returnFlightid、座席);
}
}
この実装には、特定の工場クラスの作成が含まれることがわかりました。どこかに保存されている構成情報を読み取り、Iflightdaoを作成するための実装がどのように作成されるかを理解する可能性があります。サービスがコンテナによって注入された依存関係を明示的に作成していない場合、構成の詳細とオブジェクトの作成がコンテナにプロキシ化されます。これにより、アプリケーション内のコンポーネントをさまざまな構成で簡単に接続し、昔ながらのシングルトンとファクトリーコードを排除できます。
JSR 250リソース注釈で宣言されたiflightdaoの実装に依存するクラスの実装は、次のようになるかもしれません。
Public Class TravelAgencyServiceImpl IttravelagencyServiceを実装します
{
@Resource(name = "FlightDao")
Public Iflightdao Flightdao;
Public void Booktrip(長いアウトバウンドflightid、long returnflightid、intシート)
InvalidSeatsexceptionをスローします
{
ReserveSeats(outboundflightid、座席);
ReserveSeats(returnFlightid、座席);
}
}
この場合、コンテナは「FlightDao」という名前のリソースの正しい実装をサービスクラスに提供します。しかし、EJB 3.0リリースを待つ代わりに、今すぐリソースインジェクションを活用したい場合はどうでしょうか? OK、軽量コンテナを取ることができます - スプリングやピコ容器などの依存噴射を提供できます。ただし、軽量の容器があることはわかりません。JSR250リソースアノテーションを使用して注入要件を指定することができます(この点でいくつかを楽しみにしています)。
1つの解決策は、側面を使用して依存関係噴射を実装することです。このために@Resourceアノテーションを使用する場合、実装はEJB 3.0の方法とEJB 3.0の実装と互換性のあるフォワードと一致します。次のリストは、aspectJで作成されたアスペクトを示しています - @Resourceアノテーションで注釈が付けられたフィールドを注入します。
@側面
パブリッククラスの注入症
{
Private DependencyManager Manager = new DependencyManager();
@before( "get(@resource * *。 *)")
fieldaccessesの前のpublic void(joinpoint thisjoinpoint)
IllegalargumentException、IllegalarAccessexceptionを投げます
{
FieldSignature Signature =(FieldSignature)thisjoinpoint.getSignature();
Resource InjectAnnotation = Signature.getField()。getAnnotation(resource.class);
オブジェクト依存関係= manager.resolve依存関係(signature.getfieldtype()、injectannotation.name());
signature.getfield()。set(thisjoinpoint.getthis()、依存関係);
}
}
この単純な側面はすべて、プロパティファイル(このロジックはDependencyManagerオブジェクトにカプセル化されている)からの実装クラスをクエリし、フィールドにアクセスする前に@Resourceアノテーションが注釈されたフィールドに注入することです。明らかに、この実装は完全ではありませんが、EJBなしでJSR 250互換的な方法でリソースインジェクションを提供する方法を示しています。
4。安全
リソースインジェクションに加えて、JSR 250およびEJB 3.0は、注釈を介してメタデータセキュア表現も提供します。 javax.annotation.securityパッケージは、5つのアノテーション - ランサ、役割、permitall、denyall、およびcholesreferencedを定義します。これらはすべて、セキュリティ要件を定義する方法に適用できます。たとえば、上記のBookFlightメソッドが「ユーザー」の役割を持つ発信者のみが実行できることを宣言したい場合は、次のセキュリティ制約でこの方法に注釈を付けることができます。
Public Class TravelAgencyServiceImpl IttravelagencyServiceを実装します
{
@Resource(name = "FlightDao")
Public Iflightdao Flightdao;
@RolesAllowed( "user")
Public void Booktrip(長いアウトバウンドflightid、long returnflightid、intシート)
InvalidSeatsexceptionをスローします
{
ReserveSeats(outboundflightid、座席);
ReserveSeats(returnFlightid、座席);
}
}
この注釈は、コンテナが指定された役割の発信者のみがこの方法を実行できるようにする責任があると述べます。それで、私は別の簡単な側面を示します - それはアプリケーションのセキュリティの制約をさらに強化します:
@側面
パブリッククラスのセキュリティの拡張
{
@Around( "execution(@javax.annotation.security.lolesallwed *。 *(..))")
scuredMethodsの周りの公開オブジェクト(ProceingJoinpoint thisjoinpoint)
投げられるスロー
{
boolean callerauthorized = false;
Rolesallowed chololesallowed = chololesallowedforjoinpoint(thisjoinpoint);
for(文字列の役割:cholesallowed.value())
{
if(callerinlole(role))
{callerauthorized = true;
}
if(callerauthorized)
{return thisjoinpoint.proceed();
それ以外
{
新しいruntimeexception(「指定された関数を実行することを許可されていない発信者」)を投げる);
}
}
プライベートロールアラウドロールアロウドフォージョインポイント(ProceingJoinPoint thisjoinpoint)
{
Methodsignature Methodsignature =(Methodignature)thisjoinpoint.getSignature();
メソッドTARGETMETHOD = MethodIgnature.GetMethod();
return targetmethod.getannotation(cholesallowed.class);
}
プライベートブールCallerininrole(文字列の役割)
{...}
}
この側面には、すべての方法の実行が含まれます。発信者が注釈で指定された役割の1つであることを確認することにより、@rolesallowed Annotationで注釈を付け、発信者がメソッドを呼び出すことを許可されていることを確認します。もちろん、ユーザーを承認し、JAASやカスタマイズされたソリューションなど、ユーザー/彼女の役割を取得するために好きなアルゴリズムを使用することもできます。この例プログラムでは、便利なため、サーブレットコンテナを紹介することを選択しました。
V.問題
トランザクションは、エンタープライズ開発の重要な部分になります。これは、同時環境でのデータ統合を促進するためです。高レベルから、トランザクションは複数または完全または不完全な操作を通じてこれを確実にすることができます。
リソースインジェクションとセキュリティの注釈とは異なり、トランザクションの注釈はEJB 3.0に固有であり、JSR 250通常の注釈では定義されていません。 EJB 3.0は、トランザクションに関連する2つの注釈を定義します。TransactionManagementとTransactionAttributeです。 TransactionManagerアノテーションは、トランザクションがコンテナによって管理されるのか、豆によって管理されるかを指定します。 EJB 3では、この注釈が指定されていない場合、コンテナによって管理されるトランザクションが使用されます。 TransactionAttribute Annotationは、メソッドのトランザクション伝播レベルを指定するために使用されます。既存のトランザクションが必要かどうかを定義するために、必須、必須、必要、必要、必要な、サポートされていない、サポートされていない、サポートされていないことを含む有効な値が使用されます。
BookFlight操作は、トランザクションにパッケージ化することにより、アウトバウンドフライトと帰り飛行の注文の2つのステップで構成されているため、操作の一貫性を確保できます。 EJB 3.0トランザクションアノテーションを使用することにより、これは次のようになります。
Public Class TravelAgencyServiceImpl IttravelagencyServiceを実装します
{
@Resource(name = "FlightDao")
Public Iflightdao Flightdao;
@RolesAllowed( "user")
@transactionAttribute(transactionAttributeType.Required)
Public void Booktrip(長いアウトバウンドflightid、long returnflightid、intシート)
InvalidSeatsexceptionをスローします
{
ReserveSeats(outboundflightid、座席);
ReserveSeats(returnFlightid、座席);
}
}
また、単純な側面を適用して、トランザクションの境界を自動的に定義できます。
@側面
パブリッククラスのトランザクションアシュ
{
@pointcut( "execution(@javax.ejb.transactionAttribute *。 *(..))")
public void transactionalMethods(){}
@before( "transactionalmethods()")
public void beforetransactionalmethods()
{hibernateutil.begintransaction();
@afterturning( "transactionalmethods()")
public void afterReturningTransactionAlmethods()
{hibernateutil.committransaction();
@afterthrowing( "transactionalmethods()")
throwingTransactionAlmethods()の後のパブリックボイド
{hibernateutil.rollbacktransaction();
}
この実装は、冬眠およびユビキタスなスレッドローカルパターンが、冬眠セッションとトランザクションオブジェクトを管理するために使用されるという仮定に基づいています。
6。概要
EJB 3.0およびJSR 250アノテーションセットを使用することにより、この記事では、リソース管理、セキュリティ、トランザクションなどの交差懸念がどのようにアスペクトとして実装されているかを示しています。もちろん、さらに学ぶ必要がある他の多くの内容があります。最初に学ぶべきことは、AspectJを使用してこれらの例のアスペクトを実装することにより、モジュール式のクロスカットの懸念によって提供される青写真です。第二に、現在出現しているEJB 3.0ステートメントの背後にあるいくつかの新しいアイデアと概念を見てきました。最後に、EJB APIからビジネスオブジェクトを分離するために提供されなければならない自由を劇的に見ています。この時点で、TravelAgencyServiceImplを作成したいのは、ステートレスセッションを行うことだけです。最後のメモを追加することだけです。
@stateful
Public Class TravelAgencyServiceImpl IttravelagencyServiceを実装します
{...}
最後に、エンタープライズサービスを提供するためのこの無料のアプローチが、フレームワーク/コンテナ業界の競争と革新をもたらすことを本当に願っています。