ホームページ > 記事 > ウェブフロントエンド > Avalonjs の詳しい紹介
Avalon の簡単な歴史と、それを作成したすべての設計原則の概要
物事は Apache JServ プロジェクトから始まりました。 Apache JServ の開発を支援した Stefano Mazzocchi らは、プロジェクトで使用されているパターンの一部がサーバー フレームワークの作成に使用できるほど一般的であることに気づきました。 1999 年 1 月 27 日水曜日 (JServ 1.0b のリリースから約 1 か月後)、Stefano は Java Apache Server Framework と呼ばれるプロジェクトを開始する提案を思いつきました。その目標は、Apache のすべての Java サーバー コードの基盤となることです。そのアイデアは、フレームワークを提供することで、いくつかのコンポーネントを一元化し、プロジェクト全体でコードを再利用することです。
Stefano Mazzocchi、Federico Barbieri、Pierpaolo Fumagalli がオリジナル版を作成しました。 2000 年後半、ベリン・ロリッチュとピーター・ドナルドがプロジェクトに加わりました。その時までに、Pierpaolo と Stefano は他のプロジェクトの開発に目を向けており、Java Apache Server Framework は Avalon と呼ばれるようになりました。これら 5 人の開発者は主に、フレームワークの現在のバージョンで使用される設計と概念を担当します。現在のバージョンは、2000 年 6 月にリリースされたバージョンと非常によく似ています。実際、主な違いは、パッケージの再編成とプロジェクトのサブプロジェクトへの分割です。同じデザイン パターンとインターフェイスが現在も存在しています。
Avalon とは何ですか?
Avalon は、Framework、Excalibur、LogKit、Phoenix、Cornerstone の 5 つのサブプロジェクトの親プロジェクトです。 Avalon と聞くと、ほとんどの人は Framework を思い浮かべますが、Avalon には Framework だけではありません。 Avalon は、フレームワーク、ツール、コンポーネント、サーバー コア実装がすべて 1 つのプロジェクトで構成された Java Apache Server Framework として始まりました。 Avalon の各部分には成熟度のレベルとリリース サイクルが異なるため、Avalon を前述の小さなプロジェクトに分割することにしました。そうすることで、新しい開発者が Avalon のさまざまな部分を理解し、学習することも容易になります。これは、以前はほとんど不可能でした。フレームワーク
Avalon Framework は、Avalon 傘下の他のすべてのプロジェクトの基盤です。これは、Avalon のインターフェイス、コントラクト、およびデフォルトの実装を定義します。 Framework はほとんどの作業をフレームワーク内に配置するため、最も成熟したプロジェクトでもあります。
Excalibur
Avalon Excalibur は、独自のプロジェクトで使用できるサーバー側コンポーネントのセットです。これには、プーリング、データベース接続管理、その他のコンポーネント管理の実装が含まれます。
LogKit
Avalon LogKit は、Framework、Excalibur、Cornerstone、Phoenix で使用される高速ロギング ツールセットです。このモデルは JDK 1.4 Logging パッケージと同じ原則を使用しますが、JDK 1.2 以降と互換性があります。
Phoenix
Avalon Phoenix は、サービス (ブロックと呼ばれるサーバー側コンポーネントとして実装されるサービス) のリリースと実行を管理するサーバーのコアです。
Cornerstone
Avalon Cornerstone は、Phoenix 環境にデプロイできるブロックまたはサービスのセットです。これらのブロックには、ソケット管理とブロック間のタスク スケジューリングが含まれます。
Scratchpad
Scratchpad は実際には公式プロジェクトではありませんが、まだ Excalibur に組み込む準備ができていないコンポーネントのステージング領域です。これらのコンポーネントの品質は大きく異なり、Excalibur プロジェクトに昇格するまで API が変更されない保証はありません。
この概要のハイライト
この概要では、Avalon Framework に焦点を当てますが、Avalon Excalibur と Avalon LogKit についても十分に説明しているので、すぐに始めることができます。仮想のビジネスサーバーを使用して、実際に Avalon を使用する方法を示します。完全かつ包括的な方法論を定義したり、すべてのサブプロジェクトのすべての側面を提示したりすることは、この概要の範囲を超えています。 Avalon フレームワークは他のすべてのプロジェクトの基盤であるため、Avalon フレームワークに焦点を当てます。フレームワークを理解できれば、Avalon ベースのプロジェクトを理解できます。また、Avalon で一般的に使用されるいくつかの一般的なプログラミングイディオム (イディオム) にも慣れることができます。フレームワークに焦点を当て、Avalon Excalibur プロジェクトと Avalon LogKit プロジェクトに関与するもう 1 つの理由は、それらが正式にリリースされサポートされているためです。
Avalon はどこで使用できますか?
Avalon が何に適しており、何に適していないのかを明確にしてほしいと何度か尋ねられました。 Avalon はサーバー側プログラミングに焦点を当てており、サーバー アプリケーション中心のプロジェクトの設計と保守を容易にします。 Avalon は、実装を含むフレームワークとして説明できます。 Avalon はサーバー側のソリューションに重点を置いていますが、多くの人はそれが一般的なアプリケーションにも役立つと考えています。 Framework、Excalibur、LogKit で使用される概念は、どのプロジェクトにも適用できるほど一般的です。サーバーに直接焦点を当てた 2 つのプロジェクトは、Cornerstone と Phoenix です。フレームワーク
1. サポートまたは閉じた構造2. アイデアを含む基本的なシステムまたは配置
フレームワークという言葉は、アプリケーションにおいて広い意味を持ちます。製薬システムや通信システムなど、単一の業界に焦点を当てたフレームワークは、垂直市場フレームワークと呼ばれます。その理由は、同じ枠組みが他の業界には適合しないからです。汎用性が高く、複数の業界で使用できるフレームワークは、水平市場フレームワークと呼ばれます。 Avalon は水平市場のフレームワークです。 Avalon のフレームワークを使用して、垂直市場のフレームワークを構築できます。 Avalon で構築された垂直市場フレームワークの最も説得力のある例は、Apache Cocoon パブリッシング フレームワークです。 Apache Cocoon バージョン 2 は、Avalon の Framework、Excalibur、および LogKit プロジェクトを使用して構築されています。フレームワークのインターフェイスとコントラクトを利用することで、開発者が Cocoon の仕組みを理解する時間を短縮できます。また、Excalibur が提供するデータ ソース管理コードとコンポーネント管理コードを効率的に利用できるため、車輪の再発明が不要になります。最後に、LogKit を使用して、公開フレームワーク内のすべてのログ記録の問題を処理します。 Avalon フレームワークの背後にある原則を理解すると、Avalon 上に構築されたシステムを理解できるようになります。システムを理解すると、フレームワークの誤用によって引き起こされた欠陥をより早く発見できるようになります。魔法の公式などありません
成功のための魔法の公式としてツールを使用しようとする試みは、トラブルを招くことになることは言及する価値があります。アヴァロンも例外ではありません。 Avalon のフレームワークはサーバー側ソリューション用に設計されているため、これを使用してグラフィカル ユーザー インターフェイス (GUI) を構築することは得策ではありません。 Java には、Swing と呼ばれる GUI を構築するためのフレームワークがすでにあります。 Avalon が自分のプロジェクトに適しているかどうかを検討する必要がありますが、その原理と設計から何かを学ぶことはできます。 「プロジェクトはどこで使用されるのか?」という質問が自問する必要があります。サーバー環境で実行するという答えであれば、Java サーブレットを作成する場合でも、特殊な目的のサーブレットを作成する場合でも、Avalon が適切な選択となるでしょう。サーバーアプリケーション。答えが、顧客のマシン上で実行され、サーバーと対話しないということであれば、Avalon は適切ではないかもしれません。それでも、コンポーネント モデルは非常に柔軟であり、大規模なアプリケーションの複雑さを管理するのに役立ちます。
原則とパターン
Avalon は、いくつかの特定の設計原則に基づいて構築されています。最も重要な 2 つのモードは、制御の反転と関心の分離です。コンポーネント指向プログラミング、アスペクト指向プログラミング、およびサービス指向プログラミングも Avalon に影響を与えます。それぞれのプログラミング原則は何冊もの本に相当しますが、それらはすべてデザイン思考の習慣です。制御の反転
制御の反転 (IOC) の概念は、コンポーネントが常に外部で管理されることを意味します。このフレーズは、ブライアン・フットが論文の中で初めて使用しました。コンポーネントに必要なものはすべて、コンテキスト、構成、ロガーを通じてコンポーネントに与えられます。実際、コンポーネントのライフサイクルのすべての段階は、コンポーネントを作成するコードによって制御されます。このパターンを使用すると、コンポーネントがシステムと安全に対話するためのメソッドが実装されます。 IOC はセキュリティと同義ではありません。IOC は、拡張可能なセキュリティ モデルを実装できるメカニズムを提供します。システムが真に安全であるためには、すべてのコンポーネントが安全である必要があり、どのコンポーネントも、渡されたオブジェクトの内容を変更できず、すべての対話で既知のエンティティを使用する必要があります。セキュリティは大きな懸念事項であり、IOC はセキュリティの目標を達成するためのプログラマの武器となるツールです。
懸念事項の分離
さまざまな思考方向からシステムを検討する必要があるという考えから、懸念事項の分離 (SOC) パターンが生まれました。例としては、同じ問題空間についてさまざまな視点から Web サーバーを観察することが挙げられます。 Web サーバーは安全で安定しており、管理可能で構成可能であり、HTTP 仕様を満たしている必要があります。各属性は個別に考慮する必要があります。これらの考慮事項の中には、セキュリティや安定性など、他の考慮事項に関連するものもあります (サーバーが不安定であれば、安全であるとは言えません)。分離考慮モデルは、アスペクト指向プログラミング (AOP) につながりました。研究者は、クラスまたはメソッドの粒度では多くの考慮事項に対処できないことを発見しました。これらの考慮事項はアスペクトと呼ばれます。側面の例には、オブジェクトのライフサイクルの管理、ロギング、例外の処理、リソースのクリーンアップと解放などが含まれます。安定した AOP 実装が存在しないため、Avalon 開発チームは、コンポーネントによって実装されるいくつかの小さなインターフェイスを提供することで側面や考慮事項を実装することを選択しました。
コンポーネント指向プログラミング
コンポーネント指向プログラミング (コンポーネント指向プログラミング、COP) は、システムをいくつかのコンポーネントまたは機能に分割するという考え方です。各施設には、動作するインターフェイスと、そのインターフェイスを取り囲むコントラクトがあります。このアプローチにより、システムの他の部分のコードに影響を与えることなく、コンポーネントのインスタンスを簡単に置き換えることができます。オブジェクト指向プログラミング (OOP) と COP の主な違いは、統合のレベルです。 COP システムの複雑さは、クラス間の相互依存性が少ないため、管理が容易です。これにより、コードの再利用の度合いが高まります。 COP の主な利点の 1 つは、プロジェクトのコードの一部を変更してもシステム全体が壊れないことです。もう 1 つの利点は、コンポーネントの複数の実装があり、実行時にそれらを選択できることです。
サービス指向プログラミング
サービス指向プログラミング (SOP) の考え方は、システムを、システムによって提供されるいくつかのサービスに分割することです。サービス
1. 他者のために実行される作業または義務 2. 修理またはメンテナンスを提供する施設 3. 一般にツールを提供する施設
Avalon のフェニックスでは、特定のインターフェースと関連する契約で構成されるすべての施設がサービスとして提供されると考えています。サービスの実装はブロックと呼ばれます。サーバー プログラムは複数のサービスで構成されていることを理解することが重要です。メール サーバーを例に挙げると、プロトコル処理サービス、認証および認可サービス、管理サービス、およびコア メール処理サービスが含まれます。 Avalon の Cornerstone は、独自のシステムで利用できる低レベルのサービスをいくつか提供します。提供されるサービスには、接続管理、ソケット管理、参加者/役割の管理、スケジュール設定などが含まれます。ここでは、仮想システムをさまざまな施設に分解するプロセスに関連するサービスを紹介します。
システムを分解する
コンポーネントを構成するものをどのように決定しますか? 重要なのは、ソリューションが効率的に動作するために必要な機能を定義することです。
仮想のビジネス サーバーを使用して、サービスとコンポーネントを識別して決定する方法を示します。システムで使用されるいくつかのサービスを定義した後、これらのサービスの 1 つを例として、そのサービスに必要なさまざまなコンポーネントを定義します。私の目標は、システムを管理可能な部分に定義するのに役立ついくつかの概念を伝えることです。
システム分析 - コンポーネントの特定
完全かつ包括的な方法論を提供することはこの記事の範囲を超えていますが、いくつかの問題について説明したいと思います。コンポーネントとサービスの実装指向の定義から始めて、次に実用的な定義を提供します。コンポーネント
コンポーネントは、ワーカー インターフェイスとそのワーカー インターフェイスの実装の組み合わせです。コンポーネントを使用すると、オブジェクト間の疎結合が実現し、それを使用するコードに影響を与えることなく実装を変更できます。
サービス
サービスは 1 つ以上のコンポーネントで構成され、完全なソリューションを提供します。サービスの例には、プロトコル ハンドラー、タスク スケジューラー、認証および認可サービスなどが含まれます。
これらの定義は出発点を提供しますが、完全な全体像を提供するものではありません。システム (プロジェクトを構成する一連の設備として定義される) を必要なコンポーネントに分割するには、トップダウンのアプローチを使用することをお勧めします。このアプローチにより、利用可能なものを正確に知る前に詳細に行き詰まることがなくなります。プロジェクトの範囲を決定します
プロジェクトがどのような機能を達成することが期待されるのか、最初に常に一般的なアイデアを持っておく必要があります。ビジネスの世界では、最初の作業明細書で十分です。オープンソースの世界では、これは通常、アイデアまたはブレインストーミング プロセスによって行われます。プロジェクトを俯瞰的に見ることの重要性は、どれだけ強調してもしすぎることはないと思います。大規模なプロジェクトは多くの異なるサービスで構成されますが、小規模なプロジェクトには 1 つまたは 2 つのサービスしか含まれないことは明らかです。少し圧倒され始めた場合は、大きなプロジェクトは、実際には 1 つの大きな傘の下にある多数の小さなプロジェクトであることを思い出してください。最終的には、システム全体の全体像を理解できるようになります。
作品説明: Business Server
Business Server (ビジネスサーバー) は架空のプロジェクトです。ここでの説明では、その機能は、販売注文の処理、顧客への請求の自動化、および在庫管理の管理です。販売注文は到着したら、何らかのトランザクション システムを通じて処理する必要があります。サーバーは、販売注文が完了してから 30 日後に顧客に請求書を自動的に発行します。在庫はサーバーと工場または倉庫の現在の在庫レベルの両方によって管理されます。ビジネス サーバーは分散システムとなり、各サーバーはメッセージング サービスを通じて他のサーバーと通信します。
サービスの検出
この Business Server プロジェクトを使用してサービスを検出します。上記の非常に一般的な作業記述を考慮すると、プロジェクトの説明で定義されているサービスのいくつかがすぐにわかります。サービスのリストは、明示的サービス (作業記述から直接導出できるサービス) と暗黙的サービス (同様の作業に基づいて発見されたサービス、または明示的サービスをサポートするサービス) の 2 つの大きなカテゴリに分類できます。システムを実装する企業は、すべてのサービスを自社で開発する必要はないことに注意してください。一部のサービスは商用ソリューションとして購入できます。そのような場合、決定論的な方法で商用製品と相互運用できるようにするラッパーを開発する可能性があります。システムを導入する企業がほとんどのサービスを構築します。明示的なサービス
作業明細書から、いくつかのサービスを簡単にエクスポートできます。ただし、一部のサービスの定義には他のサービスの存在を保証する必要があるため、この初期分析は作業が完了したことを意味するものではありません。トランザクション処理サービス
職務内容には、「販売注文は到着次第処理する必要がある」と明確に記載されています。これは、販売リクエストを受け入れて自動的に処理するメカニズムが必要であることを示唆しています。これは、Web サーバーの仕組みと似ています。リソースに対するリクエストを受信し、それを処理して、結果 (HTML ページなど) を返します。これをトランザクション処理といいます。最後に、トランザクションにはさまざまな種類があります。この一般的なトランザクション処理サービスは、おそらく「販売注文プロセッサ」などのより具体的なものに分割する必要があるでしょう。正確な方法はサービスの汎用性によって異なります。使いやすさと再利用性のバランスが取れています。サービスが汎用的であればあるほど、再利用可能になります。また、通常は理解するのがより困難です。
スケジュール サービス
場合によっては、トランザクションが完了した後、特定の期間が経過した後にイベントをスケジュールする必要があります。さらに、在庫管理プロセスでは定期的に発注書を発行できる必要があります。ジョブ記述には「販売注文が完了してから 30 日後に、サーバーが自動的に顧客に請求書を発行する」と記載されているため、スケジューリング サービスが必要です。幸いなことに、Avalon Cornerstone が提供するので、自分で作成する必要はありません。
メッセージサービス
作品説明には、分散システムでは「各サーバーはメッセージサービスを通じて他のサーバーと通信する」と記載されています。考えてみましょう。ユーザーは時々、特定の製品や使用したい方法を望んでいます。メッセージング サービスは、他社製品を活用する代表的な例です。おそらく、メッセージング サービスのインターフェイスとして Java Messaging Service (JMS) を使用することになります。 JMS は標準であるため、そのインターフェイスがすぐに変更される可能性は低いです。実際の経験から、明確に定義されたメッセージ指向システムは、オブジェクト指向システム (EJB など) よりも拡張性が高くなります。スケーラビリティが向上する理由の 1 つは、一般にメッセージの同時メモリ オーバーヘッドが少ないことです。もう 1 つの理由は、すべての処理を小さなサーバー クラスター (または単一のサーバー) に集中させるよりも、メッセージ処理の負荷をすべてのサーバーに分散する方が簡単であることです。
在庫管理サービス
これは教科書的な古典的なサービスではありませんが、このシステムの要件です。在庫管理サービスは、工場または倉庫の在庫記録を常に監視し、在庫が少なくなり始めるとイベントをトリガーします。
暗黙的サービス
過去のシステムで得た経験を利用して、システムをさらに他のサービスに分解すると、明示的には指定されていないがシステムに必要なサービスがいくつか得られます。スペースの都合上、詳細な内訳は行いません。認証および認可サービス
認証および認可サービスは職務内容に明示的に記載されていませんが、すべてのビジネス システムはセキュリティを真剣に考慮する必要があります。これは、システムのすべてのクライアントが認証され、すべてのユーザーのアクションが承認される必要があることを意味します。
ワークフロー自動化サービス
ワークフロー自動化は、エンタープライズ システムで人気の開発領域です。サードパーティのワークフロー管理サーバーを使用しない場合は、自分でワークフロー管理サーバーを作成する必要があります。通常、ワークフローの自動化では、ソフトウェア システムを使用して企業のビジネス プロセス全体にわたってタスクをスケジュールします。詳細については、ワークフロー管理評議会の Web サイト http://www.wfmc.org/ を参照してください。
ドキュメント センター サービス
タスクの現在のステータス情報としての「ドキュメント センター」という言葉の定義は非常に不正確です。言い換えれば、企業が注文書を受け取ると、システムは注文書情報を保存し、呼び出すことができる必要があります。請求には、在庫から新しいユーザーのリクエストに至るまで、システム内の他のプロセスと同じ要件があります。
まとめ
Business Server プロジェクトのサービスの例が、さらに多くの発見に役立つことを願っています。上位の抽象化レイヤーから下位の抽象化レイヤーに移行するにつれて、開いているポートでリクエストを処理するための接続サービスなど、より多くの種類のサービスが必要になることがわかります。私たちが定義するサービスの一部は、メッセージング サービスやワークフロー管理サービスなどのサードパーティ システムを通じて実装されます。これらのサービスでは、後でプロバイダーを切り替えることができるように、標準インターフェイスを使用することが最善です。サービスの中には、実際には複数のサービスから構成される大きなサービスもあります。一部のサービスは、Avalon Excalibur または Avalon Cornerstone ですでに提供されています。システム内のサービスを検出するときに留意すべき点の 1 つは、サービスは上位レベルのサブシステムである必要があるということです。これは、アナリストのチームを通じてコンポーネントを定義するのに役立ちます。主要なサービスを特定したため、複数の個人 (またはチーム) が各サービスを並行して分析することができます。サブシステムの境界も明確に定義されており、重複する可能性はほとんどありません。並行分析を行うことにした場合は、共通のコンポーネントを遡って特定し、可能な限り再利用できるようにする必要があります。
ビジネス サーバーの UML 図
コンポーネントの検出
適切なコンポーネントを特定するプロセスを説明するために、例として前述のドキュメント センター サービスを使用します。議論のために、ドキュメント センター サービスの要件をリストします。ドキュメント センターはデータベースを永続ストレージとして使用し、クライアントを認証し、ドキュメントをメモリにキャッシュします。コンポーネントの実践的な定義
コンポーネントについて話すときは、次の観点から考える必要があります。サービスが動作するためにどのような機能が必要か? Avalon はシステムをキャストするという概念を信じています。システムの開発者は、コンポーネントの役割と呼ばれる、コンポーネントに対する責任のリストに直面します。役割とは何ですか?
役割の概念は演劇から来ています。演劇、ミュージカル、映画では、俳優が一定数の登場人物を演じます。俳優が不足しているようには見えませんが、役の数は限られています。番組の台本は、キャラクターの役割や行動を定義します。劇場で何が起こるかのように、脚本によってコンポーネントとどのように対話するかが決まります。システム内のさまざまなアクターについて考え、コンポーネントをアクターに投影し、それらと対話します。ロールは、コンポーネントのクラスに対する契約です。たとえば、ドキュメント センター サービスにはデータベースの操作が必要です。 Avalon Excalibur は、「データソース」ロールのニーズを満たすコンポーネントを定義します。 Excalibur には 2 つの異なるコンポーネントがあり、どちらもこの役割のニーズを満たしています。どちらを使用するかはサービスの環境によって異なりますが、すべて同じ契約を満たします。多くの Avalon ベースのシステムは、キャラクターごとに 1 つのアクティブ コンポーネントのみを使用します。スクリプトは作業インターフェイス、つまり他のコンポーネントが対話するインターフェイスです。コンポーネントのインターフェイスを決定するときは、明確な契約を作成し、それを念頭に置く必要があります。契約では、コンポーネントのユーザーが何を提供しなければならないか、またコンポーネントが何を生成するかを規定します。場合によっては、使用セマンティクスを契約に含める必要があります。例としては、一時ストレージ コンポーネントと永続ストレージ コンポーネントの違いがあります。インターフェイスとプロトコルを定義したら、それらの実装に取り組むことができます。
適切なコンポーネントの候補は何ですか?
ドキュメント センター サービスでは、DataSourceComponent (Excalibur から)、Cache、Repository、Guardian の 4 つのコンポーネントが考えられます。対話がシームレスに行われる、複数の実装が存在する可能性が高い役割を探す必要があります。この例を通して、代替施設を使用する必要がある状況があることがわかります。ほとんどの場合、この機能の実装は 1 つだけ使用しますが、システムの残りの部分に影響を与えることなく、独立してアップグレードできる必要があります。他の場合には、環境に応じて異なる実装を使用する必要があります。たとえば、Excaliber によって定義された「データ ソース」は通常、すべての JDBC 接続プーリング自体を処理しますが、Java 2 Enterprise Edition (J2EE) で提供される機能を利用したい場合もあります。 Excalibur は、1 つの「データ ソース」コンポーネントで JDBC 接続とプールを直接管理し、別のコンポーネントで Java の Naming and Directory Interface (JNDI) を使用して特定の接続を取得することで、この問題を解決します。
良いコンポーネントではないものは何ですか?
JavaBeans の使用に慣れている人は、すべてを JavaBean として実装することを好みます。これは、データ モデルからトランザクション処理までのすべてを意味します。このようにコンポーネントにアプローチすると、過度に複雑なシステムが完成する可能性があります。コンポーネントは、データのモデルではなく、サービスまたは機能のモデルとして考えてください。他のソースからデータを取得するコンポーネントを使用することもできますが、データはデータのままである必要があります。 Avalon Excalibur におけるこの哲学の一例は、接続がコンポーネントではないということです。もう 1 つの例は、前述した Guardian コンポーネントです。 Guardian に含まれるロジックは、Document Center サービスとの関連性が高すぎるため、まったく別のサービスのコンポーネントとして使用することはできないと主張することもできます。複雑さを管理する方法や柔軟性を高める方法はたくさんありますが、追加の作業をする価値がない場合もあります。この場合、決定を慎重に検討する必要があります。潜在的なコンポーネントのロジックが一貫して適用される場合は、それをコンポーネントとして扱うことが合理的である可能性があります。システム内にはコンポーネントの複数のインスタンスが存在することがあり、それらは実行時に選択できます。基礎となるコンポーネントのロジックが別のコンポーネントによってのみ決定される場合、そのロジックをその他のコンポーネントに組み込むことができる場合があります。 Guardian コンポーネントとリポジトリ コンポーネントの例を通して、Guardian はリポジトリに重点を置きすぎており、コンポーネントとして実装されていないと主張できます。
ドキュメント センター サービスの内訳
実装されるコンポーネントを、その役割、根本原因、およびソース (コンポーネントがすでに存在する場合) とともにリストします。 DocumentRepository
DocumentRepository は、サービス全体の親コンポーネントです。 Avalon では、サービスは特定のタイプのコンポーネントであるブロックとして実装されます。ブロックには、サービス マーカー インターフェイスを拡張する動作インターフェイスが必要です。 Block インターフェースは、Avalon の Component インターフェースも拡張します。 Block と Service は Avalon Phoenix に含まれるインターフェイスであることに注意してください。最後に、サービスは技術的には依然として特定の種類のコンポーネントです。 DocumentRepository は、永続ストレージから Document オブジェクトを取得する方法です。サービス内の他のコンポーネントと対話して、セキュリティ、機能、速度を提供します。この特定の DocumentRepository はデータベースに接続し、内部でデータベース ロジックを使用して Document オブジェクトを構築します。
DataSourceComponent
DataSourceComponent は Avalon Excalibur によって提供されます。これは、有効な JDBC 接続オブジェクトを取得する方法です。
キャッシュ
キャッシュは、短期間のメモリ内ストレージ施設です。 DocumentRepository は、これを使用して Document オブジェクトを保存し、ハッシュ アルゴリズムを通じてそれらを参照します。キャッシュ コンポーネントの再利用性を向上させるために、保存されたオブジェクトは Cacheable インターフェイスを実装する必要があります。
Guardian
Guardian コンポーネントの役割は、参加者の管理権限に基づいています。 Guardian はデータベースからライセンス ルールセットをロードします。 Guardian は、標準の Java セキュリティ モデルを使用して、特定のドキュメントへのアクセスを保証します。
まとめ
ここまでで、優れたコンポーネントとは何かについて、ある程度理解できたはずです。この例では、ドキュメント センター サービスのすべてのコンポーネントについて説明し、それらが実行する作業を簡単に紹介します。このリストを一目見ると、施設をデータではなくコンポーネントとして実装するアプローチがわかります。ここまでで、サービスが動作する必要があるコンポーネントを判断できるはずです。
フレームワークと基盤
実際にコンポーネントを作成するための基礎を築くために、Avalon のコントラクトとインターフェイスについて説明します。
Avalon Framework は、Avalon プロジェクト全体の中心部分です。フレームワークによって定義されたコントラクトと構造を理解していれば、そのフレームワークを利用するコードを理解できます。これまで説明してきた原則とパターンを思い出してください。このセクションでは、ロールの概念が実際にどのように機能するか、コンポーネントのライフサイクル、インターフェイスがどのように機能するかについて詳しく説明します。
コンポーネントの役割を定義する
Avalon では、すべてのコンポーネントが役割を果たします。その理由は、ロールを通じてコンポーネントを取得するためです。この分野で考慮しなければならないのは、キャラクターの署名だけです。第 2 部でコンポーネントを「作業インターフェイスとその作業インターフェイスの実装の組み合わせ」として定義したことを思い出してください。作業インターフェイスが役割です。ロールのインターフェイスを作成する
以下にインターフェイスの例と、いくつかのベスト プラクティスとその理由を示します。 package org.apache.bizserver.docs;public interface DocumentRepository extends Component{ String ROLE = DocumentRepository.class.getName(); Document getDocument(Principal requestor, int refId);}
ベストプラクティス
· 「ROLE」という名前のファイルが含まれていますキャラクターの正式名を表す文字列。この名前は、ワーカー インターフェイスの完全修飾名と同じです。これは、将来コンポーネントのインスタンスを取得する必要があるときに役立ちます。 · 可能であれば、コンポーネント インターフェイスを拡張してください。これにより、コンポーネントの公開が容易になります。作業インターフェイスを制御する責任がない場合、これは役に立ちません。公開するときにいつでも Component のインスタンスにキャストできるため、それほど大きな問題はありません。 · 一つのことをしっかりやる。コンポーネントのインターフェースは可能な限りシンプルである必要があります。作業インターフェイスが他のインターフェイスを拡張している場合、コンポーネントのコントラクトを理解することが難しくなります。アメリカの古い頭字語は、この点をうまく表現しています。Keep It Simple, Stupid (KISS) です。自分よりも賢くなる(そして愚かになる)のは難しいことではありません。私自身も何度かそうしたことがあります。 · 必要なメソッドのみを特定します。クライアント プログラムは実装の詳細を知る必要はなく、代替メソッドが多すぎると不必要な複雑さが生じるだけです。言い換えれば、方法を選択し、それを貫くということです。 · キャラクターのインターフェースによってライフサイクルやサバイバルのインターフェースを拡張させないでください。このようなクラスまたはインターフェイスを実装する場合、仕様を実装しようとしているということになります。これは良いパターンではなく、将来的にはデバッグと実装の問題が発生するだけです。
キャラクター名を選択してください
Avalon では、すべてのキャラクターに名前があります。これは、システム内の他のコンポーネントへの参照を取得する方法です。 Avalon 開発チームは、キャラクターに名前を付けるためのいくつかの規則を概説しました。命名規則
· 作業インターフェイスの完全修飾名は通常、ロール名です。例外は、これらの一般規則の下にリストされています。この例では、理論上のコンポーネント名は「org.apache.bizserver.docs.DocumentRepository」である必要があります。これは、インターフェースの「ROLE」属性に含める必要がある名前です。 · コンポーネント セレクターを通じてコンポーネントへの参照を取得する場合、通常は最初のルールから推定されたロール名と、最後に「セレクター」という単語を使用します。この命名規則の結果は「org.apache.bizserver.docs.DocumentRepositorySelector」になります。この名前は、DocumentRepository.ROLE + "Selector" によって取得できます。 · 同じ作業インターフェイスを実装しているが、異なる目的を果たす複数のコンポーネントがある場合は、役割を分離します。ロールとは、システムにおけるコンポーネントの目的です。各キャラクター名は元のキャラクター名で始まりますが、キャラクターの目的名が /${目的} の形式で追加されます。たとえば、DocumentRePository の場合、PurchaseOrder (発注書) と Bill (請求書) の目的を持つことができます。これら 2 つのロールは、それぞれ DocumentRepository.ROLE + "/PurchaseOrder" および DocumentRepository.ROLE + "/Bill" として表現できます。
フレームワークインターフェースの概要
Avalon フレームワーク全体は、(API に従って) アクティビティ、コンポーネント、構成、コンテキスト、ロガー、パラメーター、スレッド、およびその他の 7 つの主要なカテゴリーに分類できます。各カテゴリ (その他を除く) は関心領域を表します。通常、コンポーネントは、考慮する検討の方向性を示すために、いくつかのインターフェイスを実装します。これにより、コンポーネント コンテナが各コンポーネントを一貫した方法で管理できるようになります。 Avalon インターフェースのライフサイクル
コンポーネントのさまざまな側面を個別に考慮するためにフレームワークが複数のインターフェースを実装する場合、メソッド呼び出しの順序について混乱が生じる可能性があります。 Avalon Framework はこれを実現するため、イベントのライフサイクル順序のプロトコルを開発しました。コンポーネントが関連するインターフェイスを実装していない場合、コンポーネントは単に次のイベントにジャンプして処理します。コンポーネントを作成して準備する正しい方法があるため、イベントを受信したときにコンポーネントをセットアップできます。コンポーネントのライフサイクルは、初期化フェーズ、アクティビティサービスフェーズ、破棄フェーズの 3 つのフェーズに分かれています。これらの段階は連続して発生するため、これらのイベントについて順番に説明します。なお、Java言語の都合上、ConstructionとFinalizationの動作は暗黙的に行われるため省略します。メソッド名と必要なインターフェイスをリストします。各フェーズ内にはメソッド名で識別されるステップがあります。コンポーネントが括弧内に指定されたインターフェイスを拡張する場合、これらの手順は順番に実行されます。初期化フェーズ
次のステップは順番に実行され、コンポーネントの有効期間中に 1 回だけ実行されます。 1.enableLogging() [LogEnabled] 2.contextualize() [コンテキスト化可能] 3.compose() [コンポーザブル] 4.configure() [コンフィグレーション可能] またはparameterize() [パラメータ化可能] 5.initialize() [初期化可能] 6.start () [開始可能]
アクティブ サービス フェーズ
以下のステップは順番に発生しますが、コンポーネントの存続期間中に複数回発生する可能性があります。 Suspendable インターフェイスを実装しないことを選択した場合、re で始まる手順を実行するときに正しい機能を保証するのはコンポーネントの責任であることに注意してください。 1.サスペンド() [一時停止可能] 2. recontextualize() [再コンテキスト化可能] 3. recompose() [再構成可能] 4. reconfigure() [再構成可能] 5.再開() [一時停止可能]
破壊フェーズ
次のステップが順番に発生します, コンポーネントの有効期間中に 1 回だけ発生します。 1. stop() [Startable] 2. destroy() [Disposable]
Avalon Framework Contract
このセクションでは、最も重要な部分であるコンポーネントを除き、すべてをアルファベット順に紹介します。フロントの最上部に配置します。コンポーネントを説明するために「コンテナ」または「コンテナ」を使用する場合、特別な意味があります。親コンポーネントによってインスタンス化され、制御されている子コンポーネントを意味します。 ComponentManager や ComponentSelector 経由で取得するコンポーネントのことではありません。さらに、コンテナコンポーネントが受信した一部の Avalon ステップ実行コマンドは、そのサブコンポーネントが対応するインターフェースを実装している限り、そのすべてのサブコンポーネントに伝播する必要があります。特定のインターフェイスは、Initializable、Startable、Suspendable、および Disposable です。このようにコントラクトを配置する理由は、これらのインターフェイスには特別な実行規則があるためです。コンポーネント
これは、Avalon Framework のコアです。この検討方向で定義されたインターフェイスは ComponentException をスローします。コンポーネント
すべての Avalon コンポーネントは Component インターフェースを実装する必要があります。コンポーネント マネージャーとコンポーネント セレクターはコンポーネントのみを扱います。このインターフェイスには定義されたメソッドがありません。これは単にトークン インターフェイスとして機能します。すべてのコンポーネントはパラメーターなしでデフォルトのコンストラクターを使用する必要があります。すべての設定は、Configurable または Parameterizable インターフェイスを通じて行われます。
コンポーザブル
他のコンポーネントを使用するコンポーネントは、このインターフェイスを実装する必要があります。このインターフェイスには compose() メソッドが 1 つだけあり、ComponentManager 型のパラメータを 1 つ受け取ります。このインターフェイスに関する規約では、compose() はコンポーネントの存続期間中に 1 回だけ呼び出されます。このインターフェイスは、メソッドを定義する他のインターフェイスと同様に、逆制御パターンを使用します。これはコンポーネントのコンテナによって呼び出され、コンポーネントに必要なコンポーネントのみが ComponentManager に表示されます。
再構成可能
まれに、コンポーネントに新しい ComponentManager と新しいコンポーネントと役割のマッピング関係が必要になることがあります。このような場合、再構成可能なインターフェースを実装する必要があります。メソッド名も Composable のメソッド名とは異なり、recompose() です。このインターフェイスに関する規約では、recompose() メソッドは何回でも呼び出すことができますが、コンポーネントが完全に初期化されるまでは呼び出すことができません。このメソッドが呼び出されるとき、コンポーネントは安全かつ一貫した方法でそれ自体を更新する必要があります。通常、これは、コンポーネントによって実行されるすべての操作が更新間で停止し、更新後に再開する必要があることを意味します。
アクティビティ
このインターフェイスのセットは、コンポーネントのライフサイクルの契約に関連しています。この一連のインターフェイス呼び出し中にエラーが発生した場合は、汎用例外をスローできます。使い捨て
コンポーネントが構造化された方法で不要になったことを知る必要がある場合は、Disposable インターフェイスを使用できます。コンポーネントの割り当てが解除されると、そのコンポーネントは使用できなくなります。実際には、ガベージコレクションが行われるのを待っているだけです。このインターフェイスには、パラメーターを持たないメソッド destroy() が 1 つだけあります。このインターフェイスに関する規約では、dispose() メソッドは一度呼び出され、コンポーネントの存続期間中に呼び出される最後のメソッドになります。また、コンポーネントが使用されなくなり、コンポーネントが占有しているリソースを解放する必要があることも示します。
Initializable
コンポーネントで他のコンポーネントを作成する必要がある場合、または他の初期化手順から情報を取得するために初期化操作を実行する必要がある場合、そのコンポーネントは Initializable インターフェイスを使用する必要があります。このインターフェイスには、initialize() メソッドが 1 つだけあり、パラメータはありません。このインターフェイスに関する規約では、initialize() メソッドは 1 回呼び出され、それが初期化プロセス中に呼び出される最後のメソッドになります。また、コンポーネントがアクティブであり、システム内の他のコンポーネントで使用できることも示します。
Startable
コンポーネントが有効期間中実行し続ける場合、そのコンポーネントは Startable インターフェイスを使用する必要があります。このインターフェイスは、start() と stop() という 2 つのメソッドを定義します。どちらのメソッドにもパラメータはありません。このインターフェイスに関する規約では、コンポーネントが完全に初期化された後に start() メソッドが 1 回呼び出されます。 stop() メソッドは、コンポーネントが破棄される前に 1 回呼び出されます。いずれも 2 回呼び出されることはありません。 start() は常に stop() より前に呼び出されます。このインターフェイスの実装は、(Thread.stop() メソッドとは異なり) start() メソッドと stop() メソッドをシステムを不安定にすることなく安全に実行するために必要です。
Suspendable
コンポーネントがその有効期間中に自身を一時停止できるようにする場合、そのコンポーネントは Suspendable インターフェイスを使用する必要があります。通常は常に Startable インターフェイスとともに使用されますが、これは必須ではありません。このインターフェースには、suspend() とresume() という 2 つのメソッドがあります。どちらのメソッドにもパラメータはありません。このインターフェイスを取り巻く規約は次のとおりです。suspend() とresume() は何回でも呼び出すことができますが、コンポーネントが初期化されて開始される前、またはコンポーネントが停止して破棄された後は呼び出すことができません。 一時停止されたコンポーネントでsuspend() メソッドを呼び出したり、すでに実行中のコンポーネントでresume() を呼び出しても効果はありません。
構成
このインターフェイスのセットでは、構成に関する考慮事項について説明します。必要な Configuration 要素がないなどの問題が発生すると、ConfigurationException がスローされる可能性があります。構成可能
構成に基づいて動作を決定する必要があるコンポーネントは、このインターフェイスを実装して構成オブジェクトのインスタンスを取得する必要があります。このインターフェイスには、Configuration タイプのパラメータを 1 つだけ持つconfigure() メソッドがあります。このインターフェイスに関する規約では、configure() メソッドはコンポーネントの存続期間中に 1 回呼び出されます。渡される Configuration オブジェクトは null であってはなりません。
Configuration
Configuration オブジェクトは、構成要素で構成されるツリーであり、いくつかの属性を持ちます。ある意味、構成オブジェクトは非常に単純化された DOM と考えることができます。 Configuration クラスにはメソッドが多すぎるため、この記事では紹介できません。JavaDoc ドキュメントを参照してください。構成オブジェクトから String、int、long、float、または boolean 値を取得できます。構成が存在しない場合は、デフォルト値が提供されます。属性についても同様です。子 Configuration オブジェクトを取得することもできます。この規約では、値を持つ Configuration オブジェクトには子オブジェクトを持たないことが規定されており、子オブジェクトについても同様です。親の Configuration オブジェクトを取得できないことがわかります。それがデザインの仕事です。システム構成の複雑さを軽減するために、ほとんどの場合、コンテナーは子構成オブジェクトを子コンポーネントに渡します。子コンポーネントは親の設定値にアクセスできません。このアプローチは多少の不便をもたらすかもしれませんが、Avalon チームは、妥協が必要な場合には常にセキュリティを最優先することを選択します。
再構成可能
このインターフェイスを実装するコンポーネントは、再構成可能なコンポーネントと非常によく似た動作をします。 reconfigure() メソッドは 1 つだけあります。この設計上の決定は、Re から始まるインターフェイスの学習の困難さを軽減することです。 Reconfigurable から Configurable への移行は、Recomposable から Composable への移行と同じです。
コンテキスト
Avalon のコンテキストの概念は、単純なオブジェクトをコンテナからコンポーネントに渡すメカニズムの必要性から生まれました。開発者に最大限の柔軟性を提供するために、正確なプロトコルと名前のバインディングは意図的に未定義になっています。 Context オブジェクトの使用に関する規約はシステム内で定義されますが、仕組みは同じです。 Context
Context インターフェースは get() メソッドを 1 つだけ定義します。これには Object 型のパラメータがあり、パラメータ object をキー値として持つオブジェクトを返します。 Context オブジェクトはコンテナによってアセンブルされ、サブコンポーネントに渡されます。サブコンポーネントには、Context に対する読み取り権限のみがあります。 Context が子コンポーネントに対して常に読み取り専用であること以外に、他の契約はありません。 Avalon の Context を拡張する場合は、この契約を必ず遵守してください。これは、リバース コントロール モデルの一部であり、セキュリティ設計の一部です。さらに、コンテキストは読み取り専用であるべきであるのと同じ理由で、コンテキスト内のコンテナへの参照を渡すことは適切ではありません。
コンテキスト化可能
コンテナから Context オブジェクトを受け取りたいコンポーネントは、このインターフェイスを実装する必要があります。 contextize() という名前のメソッドがあり、パラメータはコンテナによって組み立てられた Context オブジェクトです。このインターフェイスを取り巻く規約では、contextualize() はコンポーネントの有効期間中、LogEnabled の後、他の初期化メソッドの前に 1 回呼び出されます。
再コンテキスト化可能
このインターフェイスを実装するコンポーネントは、再構成可能なコンポーネントと非常によく似た動作をします。 recontextualize() というメソッドが 1 つだけあります。この設計上の決定は、Re から始まるインターフェイスの学習の難しさを軽減することです。 Recomposable が Composable になるのと同様に、Recontextualizable は Contextualizable になります。
解決可能
解決可能インターフェースは、特定のコンテキストで解決する必要があるいくつかのオブジェクトを識別するために使用されます。例としては、オブジェクトは複数の Context オブジェクトによって共有され、特定の Context に従って独自の動作が変更されます。コンテキストは、オブジェクトが返される前に、resolve() メソッドを呼び出します。
ロガー
すべてのシステムにはイベントをログに記録する機能が必要です。 Avalon は内部で LogKit プロジェクトを使用しています。 LogKit には Logger インスタンスに静的にアクセスするためのメソッドがいくつかありますが、フレームワークは逆の制御パターンを使用することを想定しています。 LogEnabled
Logger インスタンスを必要とするすべてのコンポーネントは、このインターフェイスを実装する必要があります。このインターフェースには、Avalon Framework Logger インスタンスをコンポーネントに渡すenableLogging() というメソッドがあります。このインターフェイスに関する規約では、コンポーネントの存続期間中、他の初期化手順の前に 1 回だけ呼び出されます。
Logger
Logger インターフェイスは、さまざまなログ ライブラリを抽象化するために使用されます。独自のクライアント API を提供します。 Avalon Framework は、このインターフェースを実装する 3 つのカプセル化クラス (LogKit 用の LogKitLogger、Log4J 用の Log4jLogger、および JDK1.4 ロギングメカニズム用の Jdk14Logger) を提供します。
パラメータ
Avalon は、多くの状況において、Configuration オブジェクト階層が重すぎることを認識します。したがって、名前と値のペアのアプローチを使用して、Configuration オブジェクトの代替となる Parameters オブジェクトを提案します。パラメータ化可能
設定オブジェクトの代わりにパラメータを使用したいコンポーネントは、このインターフェイスを実装します。 Parameterizable には、parameterize() というメソッドが 1 つだけあり、そのパラメータは Parameters オブジェクトです。このインターフェイスに関する規約では、コンポーネントの有効期間中に 1 回呼び出されます。このインターフェイスは、Configurable インターフェイスと互換性がありません。
Parameters
Parameters オブジェクトは、String 型名を通じて値を取得するメカニズムを提供します。値が存在しない場合にデフォルト値を使用したり、Configurable インターフェースから同じ形式で任意の値を取得したりできる便利なメソッドがあります。 Parameters オブジェクトと java.util.Property オブジェクトの間には類似点がありますが、意味的には重要な違いがあります。まず、パラメータは読み取り専用です。 第 2 に、パラメータは常に設定オブジェクトから簡単にエクスポートできます。最後に、Parameters オブジェクトが XML フラグメントからエクスポートされ、次のようになります:
Thread
スレッド マーカー (マーカー) が使用されます シグナルの基本セマンティクスコンポーネントの使用法に基づいたコンテナに関する情報。これらはスレッドの安全性を考慮しており、コンポーネントの実装にタグを提供します。ベスト プラクティスは、コンポーネントを最終的に実装するクラスまで、これらのインターフェイスの実装を延期することです。これにより、コンポーネントが ThreadSafe としてマークされているにもかかわらず、そこから派生したコンポーネント実装がスレッドセーフではないという複雑な事態が回避されます。このパッケージで定義されているインターフェイスは、LifeStyle インターフェイス ファミリと呼ばれるものの一部を形成します。別の LifeStyle インターフェイスは Excalibur パッケージの一部であり (つまり、このコア インターフェイス セットの拡張です)、Poolable は Excalibur のプール実装で定義されています。 SingleThreaded
SingleThreaded コンポーネントに関する規約では、このインターフェイスを実装するコンポーネントには複数のスレッドが同時にアクセスすることは許可されていません。各スレッドには、このコンポーネントの独自のインスタンスが必要です。もう 1 つのアプローチは、コンポーネントが要求されるたびに新しいインスタンスを作成するのではなく、コンポーネントのプールを使用することです。プールを使用するには、このインターフェイスの代わりに Avalon Excalibur の Poolable インターフェイスを実装する必要があります。
ThreadSafe
ThreadSafe コンポーネントを取り巻く規約では、コンポーネントに同時にアクセスするスレッドの数に関係なく、そのインターフェイスと実装は正常に動作します。これは柔軟な設計目標ですが、使用するテクノロジーによっては達成できない場合があります。このインターフェイスを実装するコンポーネントは通常、システム内にインスタンスを 1 つだけ持ち、他のコンポーネントはこのインスタンスを使用します。
その他
Avalon Framework のルート パッケージ内のこれらのクラスとインターフェイスには、例外階層といくつかの一般的なユーティリティ クラスが含まれます。しかし、言及する価値のあるクラスが 1 つあります。バージョン
JavaTM バージョン テクノロジは、jar パッケージ内のマニフェスト ファイルで指定されます。問題は、jar を解凍するとバージョン情報が失われ、バージョン情報は簡単に変更できるテキスト ファイルに配置されることです。これらの問題と学習曲線が急峻になると、コンポーネントとインターフェイスのバージョンを確認することが困難になります。 Avalon 開発チームは、バージョンを簡単に確認して比較できるように Version オブジェクトを設計しました。コンポーネントに Version オブジェクトを実装すると、適切なコンポーネントまたは最小バージョン番号をテストしやすくなります。
夢を実現しましょう
Avalon Framework と Avalon Excalibur を使用してサービス アプリケーションを実装する方法を説明します。 Avalon の使い方がいかに簡単かを説明します。
分析が完了したら、システムを構成するコンポーネントとサービスを作成する必要があります。 Avalon は、使用できるプログラミングの習慣を説明するだけであれば、あまり役に立ちません。しかし、それでも、これらのプログラミングの習慣とパターンを適用することは、システム全体を理解するのに役立ちます。 Avalon Excalibur は、作業を容易にするために独自のシステムで使用できるいくつかの便利なコンポーネントとツールを提供します。デモンストレーションとして、コンポーネントを定義し、リポジトリからドキュメントを取得して実装するプロセス全体を実行します。理論上のビジネス サーバーについての議論を覚えていると思いますが、このコンポーネントはサービスとして認識されました。実際の状況では、コンポーネントがサービスである状況が多くあります。
コンポーネントの実装
ここでは、コンポーネントの実装方法を定義します。前述した DocumentRepository コンポーネントを実装するプロセス全体を見ていきます。最初に理解する必要があるのは、コンポーネントがどの領域に重点を置いているかということです。次に、コンポーネントを作成および管理する方法を理解する必要があります。重点分野を選択してください
DocumentRepository コンポーネントのロールとインターフェイスを以前に定義したので、実装を作成する準備が整いました。 DocumentRepository インターフェイスではメソッドが 1 つだけ定義されているため、スレッドセーフなコンポーネントを作成できます。これは、最小限のリソース消費しか許可しないため、最も一般的なタイプのコンポーネントです。実装をスレッドセーフにするためには、コンポーネントの実装方法を慎重に検討する必要があります。すべてのドキュメントはデータベースに保存されており、外部の Guardian コンポーネントを使用したいため、他のコンポーネントにアクセスする必要があります。責任ある開発者として、私たちはコンポーネントのデバッグに役立つ情報をログに記録し、内部で何が起こっているかを追跡したいと考えています。 Avalon フレームワークの利点は、必要なインターフェイスのみを実装し、不要なインターフェイスは無視できることです。これが懸念の分離の利点です。考慮する必要のある新しい側面が見つかった場合は、関連するインターフェイスを実装するだけでコンポーネントに新しい機能を追加できます。コンポーネントを使用する部分を変更する必要はありません。スレッド セーフは設計目標であるため、ThreadSafe インターフェイスを実装する必要があることはすでにわかっています。 DocumentRepository インターフェイスにはメソッドが 1 つしかないため、このコンポーネントの作業インターフェイスを使用することでこの要件が満たされます。そして、コンポーネントは完全に初期化されるまで使用されず、破棄された後も使用されないことがわかっています。設計を完了するには、いくつかの暗黙的なインターフェイスを実装する必要があります。コンポーネントが完全に初期化されたかどうかを明示的に知ることができるように、ソリューションを十分に安全なものにしたいと考えています。この目標を達成するために、Initializable インターフェイスと Disposable インターフェイスを実装します。環境に関する情報は変更される可能性があるため、またはカスタマイズが必要になる場合があるため、DocumentRepository に Configurable インターフェースを実装させる必要があります。必要なコンポーネントのインスタンスを取得するために Avalon が提供するメソッドは、ComponentManager を使用することです。 ComponentManager からコンポーネント インスタンスを取得するには、Composable インターフェイスを実装する必要があります。 DocumentRepository はデータベース内のドキュメントにアクセスするため、決定を下す必要があります。 Avalon Excalibur DataSourceComponent を使用しますか、それともデータベース接続管理コードを独自に実装しますか。この記事ではDataSourceComponentを利用します。この時点で、クラスのスケルトンは次のようになります。 = null; /*** コンストラクター。すべてのコンポーネントが正当なコンポーネントであるためには、引数なしの public コンストラクター * が必要です。*/ public DatabaseDocumentRepository() {} /*** 構成。 * コンポーネントがすでに構成されているかどうかを確認していることに注意してください。これは、 * Configure を 1 回だけ呼び出すというポリシーを強制するために行われます。*/ public Final void configure(Configuration conf) throws ConfigurationException { if (initialized ||破棄) { throw new IllegalStateException ( "不正call"); } if (null == this.dbResource) { this.dbResource = conf.getChild("dbpool").getValue(); getLogger().debug("使用中のデータベース プール: " + this.dbResource ); // getLogger() に注目してください。これは、 // ほぼすべてのコンポーネントに対して拡張した AbstractLogEnabled からのものです。 } } /*** 構成。コンポーネントが * すでに初期化または破棄されているかどうかを確認していることに注意してください。これは、 * 適切なライフサイクル管理のポリシーを強制するために行われます。*/ public Final void compose(ComponentManager cmanager) throws ComponentException { if (initialized ||破棄されました) { throw new IllegalStateException ("不正な呼び出し"); } if (null == this.manager) { this.manager = cmanager; } } publicfinal voidinitialize() throws Exception { if (null == this.manager) { throw new IllegalStateException("未構成"); } if (null == this.dbResource) { throw new IllegalStateException("未構成"); } if (dissolved) { throw new IllegalStateException("すでに破棄されました"); .initialized = true; } public Final void destroy() { this.disposed = true; this.manager = null; this.dbResource = null; } public last Document (Principal requestor, int refId) { if (!initialized || destroy) { throw new IllegalStateException("Illegal call"); } // TODO: FILL IN LOGIC }}
上記のコードにはいくつかの構造パターンが見つかります。セキュリティを念頭に置いて設計する場合は、コンポーネント内の各コントラクトを明示的に強制する必要があります。セキュリティの強さは、最も弱い部分に応じて決まります。コンポーネントが完全に初期化されたことが確認できる場合にのみ、コンポーネントを使用してください。破棄された後は、決して再使用しないでください。このロジックをここに置いたのは、独自のクラスを作成するときと同じ方法で行うためです。
コンポーネントのインスタンス化と管理コンポーネント
コンテナとコンポーネントの関係がどのように機能するかを理解するために、まずコンポーネントを手動で管理する方法について説明します。次に、Avalon の Excalibur コンポーネント アーキテクチャが複雑さをどのように隠しているかについて説明します。コンポーネントを自分で管理したい場合もあるでしょう。しかし、ほとんどの場合、Excalibur にはユーザーのニーズを満たすパワーと柔軟性があります。手動による方法
Avalon のコンポーネントはすべてどこかで作成されます。コンポーネントを作成するコードは、コンポーネントのコンテナーです。コンテナは、構築から破棄までのコンポーネントのライフサイクルを管理します。コンテナーには、コマンド ラインから呼び出すことができる静的な「メイン」メソッドを含めることも、別のコンテナーを含めることもできます。コンテナを設計するときは、リバース コントロールのパターンを覚えておいてください。情報とメソッド呼び出しはコンテナからコンポーネントにのみ流れます。コントロールの破壊
コントロールの破壊は、リバース コントロールのアンチパターンです。 Subversion 制御は、コンテナへの参照をコンポーネントに渡すときに実現されます。これは、コンポーネントに独自のライフサイクルを管理させる場合にも当てはまります。このように動作するコードは欠陥があるとみなされます。コンテナーとコンポーネントの関係を混在させると、それらの相互作用により、システムのデバッグやセキュリティの監査が困難になります。
子コンポーネントを管理するには、そのコンポーネントの存続期間中、子コンポーネントへの参照を保持する必要があります。コンテナーと他のコンポーネントがサブコンポーネントを使用できるようにするには、初期化を完了する必要があります。 DocumentRepository の場合、コードは次のようになります。 class ContainerComponentimplements Component, Initializable, Disposable{ DocumentRepository docs = new DatabaseDocumentRepository(); GuardianComponent Guard = new DefaultComponentManager manager = new DefaultComponentManager() throws;例外 { Logger docLogger = new LogKitLogger( Hierarchy.defaultHierarchy() .getLoggerFor( "document" ) ); this.docs.enableLogging( docLogger.childLogger( "repository" ) ); this.guard.enableLogging( docLogger .childLogger( "security) " ) ); DefaultConfiguration プール = new DefaultConfiguration("dbpool"); pool.setValue("main-pool"); DefaultConfiguration conf = new DefaultConfiguration(""); conf.addChild(pool); this.manager.addComponent( DocumentRepository .ROLE、this.docs ); this.manager.addComponent( GuardianComponent.ROLE、this.guard ); this.guard.compose( this.docs.configure ); (conf); this.guard.initialize(); } public void destroy() { this.guard.dispose(); のため簡潔にするために、上記のコードから明示的なチェックを削除しました。コンポーネントを手動で作成および管理するのは、非常に複雑な作業であることがわかります。コンポーネントのライフサイクルのステップを忘れると、バグが見つかることになります。これには、インスタンス化するコンポーネントについての深い知識も必要です。別のアプローチは、上記の ContainerComponent にいくつかのメソッドを追加して、コンポーネントの初期化を動的に処理することです。
自動化された自律性
開発者は本質的に怠け者なので、システム内のすべてのコンポーネントのコンテナとして機能する特別な ComponentManager の作成に時間を費やします。こうすることで、システム内のすべてのコンポーネントのインターフェイスを深く理解する必要がなくなります。これはイライラする作業になる可能性があります。アヴァロンの開発者はそのようなモンスターを作成しました。 Avalon Excalibur のコンポーネント アーキテクチャには、XML 設定ファイルを通じて制御される ComponentManager が含まれています。コンポーネントの管理責任を Excalibur の ComponentManager に引き渡す場合には、トレードオフが発生します。 CompomentManager にどのコンポーネントを含めるかを細かく制御することはできません。ただし、システムがかなり大規模な場合、手動制御は面倒な作業になる可能性があります。この場合、システムの安定性を確保するには、システム内のすべてのコンポーネントを 1 か所から集中管理することが最善です。 Excalibur のコンポーネント アーキテクチャとの統合にはさまざまなレベルがあるため、最も低いレベルから始めます。 Excalibur には、コンポーネントの種類ごとに独立したコンテナとして機能する ComponentHandler オブジェクトのセットがあります。コンポーネントのライフサイクル全体を管理します。ライフスタイルインターフェイスの概念を紹介しましょう。生存インターフェースは、システムがコンポーネントをどのように扱うかを記述します。コンポーネントの動作方法はシステムの動作に影響を与えるため、現在の動作方法の影響について議論する必要があります。 · org.apache.avalon.framework.thread.SingleThreadedo はスレッドセーフではなく、再利用可能でもありません。 o 他のサバイバル モード インターフェイスが指定されていない場合、システムはこれを考慮します。 o コンポーネントがリクエストされるたびに、新しいインスタンスが作成されます。 o インスタンスの作成と初期化は、コンポーネントが要求されるまで延期されます。 · org.apache.avalon.framework.thread.Threadsafeo コンポーネントは完全にリエントラントであり、すべてのスレッドセーフ原則に準拠しています。 o システムはインスタンスを作成し、そのインスタンスへのアクセスはすべてのコンポーザブル コンポーネントによって共有されます。 o インスタンスの作成と初期化は、ComponentHandler が作成されるときに完了します。 · org.apache.avalon.excalibur.pool.Poolableo はスレッドセーフではありませんが、完全に再利用可能です。 o インスタンスのセットを作成し、それらをプールに置きます。コンポーザブル コンポーネントがそれを要求すると、システムは使用可能なインスタンスを提供します。 o インスタンスの作成と初期化は、ComponentHandler が作成されるときに完了します。 ComponentHandler インターフェイスは非常に簡単に処理できます。 Java クラス、Configuration オブジェクト、ComponentManager オブジェクト、Context オブジェクト、RoleManager オブジェクトを使用してコンストラクターを初期化します。コンポーネントに上記のいずれも必要ないことがわかっている場合は、代わりに null をアップロードできます。この後、コンポーネントへの参照が必要な場合は、「get」メソッドを呼び出します。完了したら、「put」メソッドを呼び出してコンポーネントを ComponentHandler に返します。次のコードは、これを理解しやすくします。 class ContainerComponent は Component、Initializable、Disposable を実装します{ ComponentHandler docs = null; ComponentHandler ガード = null; DefaultComponentManager マネージャー = new DefaultComponentManager(); 例外をスローします { DefaultConfiguration pool = new DefaultConfiguration("dbpool"); "main-pool"); DefaultConfiguration conf = new DefaultConfiguration(""); this.docs.configure(conf); this.docs = ComponentHandler.getComponentHandler( DatabaseDocumentRepository.class, this.manager 、 null、null); this.guard = ComponentHandler.getComponentHandler( DocumentGuardianComponent.class、null、this.manager、null、null); ロガー docLogger = new LogKitLogger( Hierarchy.defaultHierarchy() .getLoggerFor( "document" ) ); .docs.enableLogging( docLogger.childLogger( "repository" ) ); this.guard.enableLogging( docLogger.childLogger( "security" ) ); this.manager.addComponent(DocumentRepository.ROLE, this.docs); addComponent(GuardianComponent.ROLE, this.guard); this.guard.initialize(); } public void destroy() { this.guard.dispose(); }}
ここでは、数行のコードを見逃しただけです。それでも、Configuration オブジェクトを手動で作成し、Logger をセットアップし、さらに ComponentHandler オブジェクトを初期化して破棄する必要がありました。ここで行うことは、インターフェイスの変更による影響を防ぐことだけです。この方法でコーディングすると有益な場合があります。エクスカリバーはさらに一歩進みます。ほとんどの複雑なシステムには、いくつかの構成ファイルがあります。これらにより、管理者は重要な構成情報を調整できます。 Excalibur は、次の形式の構成ファイルを読み取り、そこからシステム コンポーネントを作成できます。
すごいと思いませんか? 2 倍以上のコード量 (13 行ではなく 6 行のコード) で 2 倍以上のコンポーネントの数を初期化しました。この構成ファイルには欠点があり、少し奇抜に見えますが、記述する必要のあるコードの量は最小限に抑えられます。 ExcaliburComponentManager の舞台裏では多くのアクティビティが行われています。 Excalibur は、構成ファイル内の「コンポーネント」要素ごとに、クラス エントリごとに ComponentHandler を作成し、ロールとの対応関係を確立します。 「component」要素とそのすべての子要素は、コンポーネントの構成です。コンポーネントが ExcaliburComponentSelector の場合、Excalibur は各「component-instance」要素を読み取り、以前と同じ種類の操作を実行し、今回はヒント エントリとの対応関係を確立します。設定ファイルの見栄えを良くする
エイリアスを使用して構成ファイルの外観を変更できます。 Excalibur は、RoleManager を使用して構成システムのエイリアスを提供します。 RoleManager は、特別に作成したクラスにすることも、DefaultRoleManager を使用して Configuration オブジェクトに渡すこともできます。 DefaultRoleManager を使用する場合は、ロール構成ファイルとシステムのその他の部分を jar ファイルに隠します。これは、キャラクターのプロフィールは開発者によってのみ変更されるためです。次に、RoleManager インターフェイスを示します。まず、Excalibur はルート要素のすべての子要素をループします。これにはすべての「コンポーネント」要素が含まれますが、今回は Excalibur が要素名を認識しないため、RoleManager にこのコンポーネントにどのような役割を使用するかを尋ねます。 RoleManager が null を返した場合、要素とそのすべての子要素は無視されます。次に、Excalibur はロール名からクラス名を導出します。最後のアプローチは、クラス名を ComponentSelector のサブタイプに動的にマップすることです。 Excalibur は、XML 構成ファイルを使用する、RoleManager のデフォルト実装を提供します。タグは非常にシンプルで、管理者に見せたくない追加情報をすべて非表示にします。
RoleManager を使用するには、以下を行う必要があります。コンテナクラスの「Initialization」メソッドを変更します。構成ビルダーを使用して、このファイルから構成ツリーを構築します。 RoleManager を使用する場合は、「configure」メソッドを呼び出す前に「setRoleManager」メソッドを呼び出す必要があることに注意してください。クラス ローダーからこの XML ファイルを取得する方法を示すために、以下の手法を示します。 DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();Configuration sysConfig = builder.buildFromFile("./conf/system.xconf");Configuration roleConfig = builder.build( this.getClass().getClassLoader() .getResourceAsStream("/org/apache/bizserver/docs/document.roles"));DefaultRoleManager ロール = new DefaultRoleManager();roles.enableLogging(Hierarchy.getDefaultHierarchy () .getLoggerFor("document.roles"));roles.configure(roleConfig);this.manager.setLogger( Hierarchy.getDefaultHierarchy() .getLoggerFor("document") );this.manager.contextualize( new DefaultContext() ); this.manager.setRoleManager(roles);this.manager.configure(sysConfig);this.manager.initialize();
6 行のコードを追加したので、それがどのようなメリットをもたらすかを見てみましょう。最終的な構成ファイルは次のように記述できます。
コンポーネントの使用
コンポーネントを作成したので、それを使用します。コンポーネントがどのように初期化および管理されるかに関係なく、コンポーネントにアクセスする方法は同じです。 ComponentManager から参照を取得するには、Composable インターフェイスを実装する必要があります。 ComponentManager は、必要なすべてのコンポーネントへの参照を保持します。説明の便宜上、取得した ComponentManager が前のセクションの最終構成ファイルに従って構成されていると仮定します。 これは、リポジトリ、ガーディアン、および 2 つのデータソースがあることを意味します。コンポーネント管理インフラストラクチャを使用する原則
コンポーネント管理インフラストラクチャでは、参照を取得するコンポーネントをリリースする必要があります。この制限の理由は、コンポーネントのリソースを適切に管理するためです。 ComponentManager は、特定の役割に対してさまざまなタイプのコンポーネントがあることを考慮して設計されています。 ComponentSelector のもう 1 つのユニークな点は、コンポーネントとしても設計されていることです。これにより、ComponentManager から ComponentSelector を取得できるようになります。外部コンポーネントへの参照を処理するには、2 つの正当な方法があります。初期化中に参照を取得し、破棄時に解放できます。コンポーネントを処理するコードを try/catch/finally ブロックに置くこともできます。どちらの方法にも長所と短所があります。初期化と破棄のアプローチ
class MyClass は Component, Composable, Disposable{ ComponentManager manager; /*** ガードへの参照を取得し、* ComponentManager への参照を保持します。*/ public void compose(ComponentManager manager) throws ComponentException { if (this.manager == null) { this.マネージャー = マネージャー; myGuard = (ガーディアン) this.manager.lookup(Guardian.ROLE); } } /**※ガーディアンを使用した方法です。*/ public void myMethod() throws SecurityException { this.myGuard.checkPermission(new BasicPermission("test") )); } /*** 私たちの参照を削除してください*/ public void destroy() { this.manager.release(this.myGuard); this.myGuard = null; this.manager = null;ほら、これは簡単です。オブジェクトが最初に ComponentManager を受け取ると、Guardian コンポーネントへの参照を取得します。 Guardian コンポーネントがスレッドセーフである (ThreadSafe インターフェイスを実装している) ことを確認できる場合は、次のことを行うだけで済みます。残念ながら、長期的にこれを保証することはできません。リソースを正しく管理するには、コンポーネントの使用が完了した後、コンポーネントへの参照を解放する必要があります。このため、ComponentManager への参照を保持します。このアプローチの主な欠点は、コンポーネント プール内のコンポーネントを操作する場合にあります。コンポーネントへの参照により、コンポーネントは存続します。オブジェクトの有効期間が短い場合は問題にならない可能性がありますが、オブジェクトが Excalibur コンポーネント管理アーキテクチャによって管理されるコンポーネントの場合、そのオブジェクトへの参照がある限りその有効期間は継続します。これは、コンポーネント プールを実際にコンポーネント ファクトリに変えることを意味します。このアプローチの主な利点は、コンポーネントを取得および解放するためのコードが明確であることです。例外処理コードを理解する必要はありません。もう 1 つの微妙な違いは、ガーディアンの存在とこのオブジェクトを初期化する機能を結び付けることです。オブジェクトの初期化フェーズ中に例外がスローされた場合は、そのオブジェクトが有効なオブジェクトではないと想定する必要があります。必要なコンポーネントが存在しない場合にプログラムが失敗するようにしたい場合がありますが、これは問題ありません。コンポーネントを設計するときは、この暗黙の意味を認識する必要があります。
例外処理アプローチ
class MyClass は Composable, Disposable{ ComponentManager manager; /*** ガードへの参照を取得し、* ComponentManager への参照を保持します。*/ public void compose(ComponentManager manager) throws ComponentException { if (this.manager == null) { this.manager = manager } } /**※ガーディアンを取得する方法です。*/ public void myMethod() throws SecurityException { Guardian myGuard = null; try { myGuard = (Guardian) this.manager.lookup(Guardian.ROLE); this.criticalSection(myGuard); ComponentException ce) { throw new SecurityException(ce.getMessage()); } catch (SecurityException se) { throw se; }finally { if (myGuard != null) { this.manager.release(myGuard); ** コードの重要な部分を実行します。*/ public voidcriticalSection(Guardian myGuard) throws SecurityException { myGuard.checkPermission(new BasicPermission("test"));
ご覧のとおり、このコードは少し複雑です。それを理解するには、例外処理を理解する必要があります。 Java 開発者の大多数は例外の処理方法を知っているため、これは問題にはならない可能性があります。 こうすることで、コンポーネントが必要でなくなるとすぐにリリースされるため、コンポーネントがどのように存続するかについてあまり心配する必要がなくなります。このアプローチの主な欠点は、より複雑な例外処理コードが追加されることです。複雑さを最小限に抑え、コードの保守を容易にするために、動作中のコードを抽出して別のメソッドに置きます。 try ブロックでは、コンポーネントへの参照を必要なだけ取得できることに注意してください。このアプローチの主な利点は、コンポーネント参照をより効率的に管理できることです。同様に、ThreadSafe コンポーネントを使用している場合には実際の違いはありませんが、コンポーネント プールのコンポーネントを使用している場合には違いがあります。コンポーネントを使用するたびにコンポーネントへの新しい参照を取得するには若干のオーバーヘッドが発生しますが、新しいコンポーネント インスタンスの作成が強制される可能性は大幅に減少します。初期化と破棄の仕組みと同様、理解する必要がある微妙な違いがあります。 例外処理は、マネージャーがコンポーネントを見つけられない場合でも、初期化中にプログラムが失敗しない方法で行われます。 前述したように、これにはまったくメリットがないわけではありません。多くの場合、特定のコンポーネントが存在することが期待されますが、期待されたコンポーネントが存在しなくてもプログラムが失敗する必要はありません。
ComponentSelector からコンポーネントを取得する
ほとんどの操作では、ComponentManager を使用するだけで済みます。 DataSourceComponent の複数のインスタンスが必要であると判断したので、必要なインスタンスを取得する方法を知る必要があります。 ComponentSelector は、処理中に目的の参照を取得するためのヒントがあるため、ComponentManagers よりも少し複雑です。 すでに明らかにしたように、コンポーネントは特定の役割に属します。 ただし、場合によっては、キャラクターの複数のコンポーネントから 1 つを選択する必要があります。 ComponentSelector は任意のオブジェクトをヒントとして使用します。ほとんどの場合、このオブジェクトは String ですが、正しく国際化されたコンポーネントを取得するために Locale オブジェクトを使用することもできます。私たちがセットアップしたシステムでは、DataSourceComponent の正しいインスタンスを選択するために文字列を使用することを選択しました。正しいコンポーネントを取得するために必要な文字列を指定するための Configuration 要素も指定しました。システム管理が容易になるため、これに従うことをお勧めします。これにより、システム管理者は、これらの魔法の構成値を覚えておく必要がなく、他のコンポーネントへの参照を簡単に確認できるようになります。概念的には、ComponentSelector からコンポーネントを取得することと、ComponentManager からコンポーネントを取得することの間に違いはありません。 あと一歩だけです。 ComponentSelector もコンポーネントであることに注意してください。 ComponentSelect のロールを検索すると、ComponentManager が ComponentSelector コンポーネントを準備して返します。次に、それを通じてコンポーネントを選択する必要があります。 これを説明するために、前に説明した例外処理コードを詳しく説明します。 public void myMethod() throws Exception{ ComponentSelector dbSelector = null; DataSourceComponent datasource = null; try { dbSelector = (ComponentSelector) this.manager.lookup(DataSourceComponent.ROLE + "Selector"); .useDb); this.process(datasource.getConnection()); } catch (Exception e) { throw e; } if (datasource != null) { dbSelector.release(datasource); ) { this.manager.release(dbSelector); } }}
指定されたコンポーネントのロールを使用して、ComponentSelector への参照を取得したことがわかります。 前述のロールの命名規則に従い、ロール名の接尾辞として「Selector」を追加しました。静的インターフェイスを使用してシステム内のすべてのロール名を処理し、コード内の文字列連結の数を減らすことができます。これも全く問題ありません。次に、ComponentSelector から DataSource コンポーネントへの参照を取得する必要があります。このコード例では、Configuration オブジェクトから必要な情報を取得し、それを「useDb」という名前のクラス変数に配置したことを前提としています。
Excalibur のツール
最後のセクションでは、Apache Avalon Excalibur が提供するいくつかのタイプのコンポーネントとツールを紹介します。 これらのツール クラスは堅牢であり、実際の運用システムで使用できます。私たちは「Scratchpad」と呼ばれる非公式の階層プロジェクトを持っており、そこで潜在的な新しいツール クラスの実装の詳細を検討しています。 Scratchpad のツールの品質はさまざまで、便利だと思われるかもしれませんが、同じ方法で使用できるという保証はありません。 コマンドラインインターフェイス (CLI)
CLI ツールクラスは、Avalon Phoenix や Apache Cocoon などの一部のプロジェクトでコマンドラインパラメーターを処理するために使用されます。ヘルプ情報を出力するメカニズムを提供し、短い名前または長い名前の形式でパラメータ オプションを処理できます。
コレクションツールクラス
コレクション ユーティリティ クラスは、JavaTM Collections API にいくつかの機能拡張を提供します。 これらの機能強化には、2 つのリストと PriorityQueue の間の交差部分を検索する機能が含まれます。これは、オブジェクトの優先順位の変更を単純な先入れ後出しスタックで実装できるようにするスタックの機能強化です。
コンポーネント管理
この側面の使用法については以前に説明しました。これは Excalibur で最も複雑なモンスターですが、わずか数クラスで多くの機能を提供します。単純な SingleThreaded または ThreadSafe 管理タイプに加えて、Poolable タイプもあります。コンポーネントが SingleThreaded インターフェイスの代わりに Excalibur の Poolable インターフェイスを実装している場合、コンポーネントのプールが維持され、インスタンスが再利用されます。ほとんどの場合、これでうまくいきます。いくつかのコンポーネントを再利用できない場合は、SingleThreaded インターフェイスが使用されます。
LogKit 管理
Avalon 開発チームは、多くの人が複雑なログ ターゲット階層を作成するためのシンプルなメカニズムを必要としていることに気づきました。チームは、RoleManager と同様のアイデアに基づいて、前述の Excalibur コンポーネント管理システムで使用できる LogKitManager を開発しました。 「logger」属性に基づいて、さまざまなコンポーネントに対応する Logger オブジェクトが提供されます。
スレッド ツール クラス
コンカレント パッケージは、マルチスレッド プログラミングを支援するいくつかのクラスを提供します: Lock (mutex の実装)、DjikstraSemaphore、ConditionalEvent、および ThreadBarrier。これは javax.sql.DataSource クラスに基づいて設計されていますが、簡略化されています。 DataSourceComponent には 2 つの実装があります。1 つは JDBC 接続プールを明示的に使用し、もう 1 つは J2EE アプリケーション サーバーの javax.sql.DataSource クラスを使用します。
入出力 (IO) ユーティリティ クラス
IO ユーティリティ クラスは、いくつかの FileFilter クラスとファイルおよび IO 関連のユーティリティ クラスを提供します。
プールの実装
Poolは、さまざまな状況で使用できるプールを実装します。実装の 1 つは非常に高速ですが、FlyWeight モードを実装するのは 1 つのスレッドでのみ使用できます。プール内のオブジェクトの数を管理しない DefaultPool もあります。 SoftResourceManagingPool は、オブジェクトが返されたときにしきい値を超えているかどうかを判断し、超えた場合、オブジェクトは「リタイア」されます。最後に、オブジェクトの最大数に達すると、HardResourceManagingPool は例外をスローします。後の 3 つのプールはすべて ThreadSafe です。
Property Utility クラス
Property Utility クラスは、Context オブジェクトとともに使用されます。これらを使用すると、Resolvable オブジェクト内の「変数」を拡張できます。その仕組みは次のとおりです。「${resource}」は、コンテキスト内で「resource」という名前の値を検索し、シンボルをその値に置き換えます。
結論
Avalon は時の試練に耐え、いつでも使用できるようになりました。このセクションで提供される証拠は、成熟したフレームワークを使用する方が自分でフレームワークを作成するよりも優れていることを自分自身や他の人に納得させるのに役立ちます。
あなたはすでに確信しているかもしれませんが、Avalon が正しい選択であることを同僚に納得させるには助けが必要です。 あなたも自分自身を納得させる必要があるかもしれません。いずれにしても、この章は自分の考えを整理し、説得力のある証拠を提供するのに役立ちます。 私たちはオープンソース モデルの恐怖、不確実性、疑念 (FUD) と戦う必要があります。 オープンソースの有効性の証拠については、この主題についての Eric S. Raymond の優れた扱いを読むことをお勧めします N400017 彼の見解についてどう考えても、彼の記事は The Cathedral という本にまとめられており、バザール情報は宣伝のために提供されます。オープンソースの一般的な受け入れ。
Avalon は機能します
私たちの結論は、Avalon は当初の目的を達成するために設計されたものを達成するということです。 Avalon は、新しい概念やアイデアを導入するのではなく、実績のあるいくつかの概念を使用し、それらを標準化します。 Avalon の設計に影響を与えた最新のコンセプトは、1995 年頃に提案された懸念の分離パターンです。当時でさえ、考慮事項の分離はシステム分析技術への正式なアプローチでした。 Avalon のユーザーベースは数百人に上ります。 Apache Cocoon、Apache JAMES、Jesktop などの一部のプロジェクトは Avalon 上に構築されています。これらのプロジェクトの開発者は、Avalon Framework のユーザーです。 Avalon は非常に多くのユーザーを抱えているため、十分にテストされています。最高の人材によって設計されました
Avalon の作成者は、私たちがサーバーサイド コンピューティングの唯一の専門家グループではないことを認識しています。私たちは他の人の研究から得たコンセプトやアイデアを使用しました。ユーザーからのフィードバックに応えます。 Avalon は、上記 5 人の開発者によって設計されただけではなく、リバース制御、分離の考慮、コンポーネント指向プログラミングのアイデアを持ち込んで設計されました。オープンソースの素晴らしい点は、その結果が最高のアイデアと最高のコードの融合であることです。 Avalon はアイデアをテストし、より良い解決策があったためにいくつかを拒否する段階を経ました。 Avalon 開発チームが得た知識を活用して、独自のシステムに適用できます。 Excalibur の事前定義されたコンポーネントは独自のプロジェクトで使用でき、高負荷下でもエラーなしで実行されることがテストされています。
互換性ライセンス
Apache ソフトウェア ライセンス (ASL) は、他の既知のライセンスと互換性があります。 既知の最大の例外は、GNU Public License (GPL) と Lesser GNU Public License (LGPL) です。重要なことは、ASL は共同開発に非常に適しており、望まない場合にソース コードのリリースを強制しないことです。に。 Apache Software Foundation から高く評価されている HTTP サーバーは、同じライセンスに基づいてライセンス供与されています。
クラスターベースの研究開発
ほとんどの Avalon ユーザーは何らかの形で貢献しています。これにより、開発、デバッグ、ドキュメントの作業負荷が多数のユーザーに分散されます。 また、Avalon のコードが、企業開発で可能となるよりも広範なピアレビューを受けていることも示しています。さらに、Avalon ユーザーは Avalon をサポートします。 通常、オープンソース プロジェクトにはホット マネーに関するヘルプ デスクや電話サポートがありませんが、私たちにはメーリング リストがあります。質問の多くは、一部のサポート ホットラインよりも早く、メーリング リスト経由で迅速に回答できます。
分析と設計の簡素化
Avalon に基づいた開発は、開発者が精神状態を達成するのに役立ちます。 このような精神状態では、開発者の仕事はコンポーネントとサービスを発見する方法に焦点を当てます。コンポーネントとサービスの寿命に関する詳細が分析および設計されたので、開発者は必要なものを選択するだけで済みます。 Avalon は、従来のオブジェクト指向の分析と設計を置き換えることから始まったわけではなく、それを強化することから始まったということを指摘することが重要です。 以前と同じテクニックを引き続き使用していますが、デザインをより迅速に実装するためのツール セットが手に入りました。
Avalon の準備が完了しました
Avalon Framework、Avalon Excalibur、および Avalon LogKit を使用する準備ができました。彼らは成熟し、さらに良くなっている。 Avalon Phoenix と Avalon Cornerstone は集中的に開発中ですが、これらに基づいて作成したコードは、わずかな変更を加えるだけで将来的にも機能します。
以上がAvalonjs の詳しい紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。