プラグインフレームワーク IPlugin#
Title: プラグインフレームワーク IPlugin
URL Source: https://newlifex.com/core/plugin
Markdown Content:
ビジネス開発でよく使用されるプラグインアーキテクチャの実装、特に外部 DLL 形式のプラグイン。私たちはプラグイン管理の汎用コードを封装しました。
ソースコード:https://github.com/NewLifeX/X/blob/master/NewLife.Core/Model/IPlugin.cs
クイックスタート#
星尘代理 StarAgentは、プラグインをロードして機能を拡張することをサポートしています。以下は星尘代理がプラグインをロードして初期化するコードです。
// プラグインマネージャー
var pm = _PluginManager = new PluginManager
{
Identity = "StarAgent",
Provider = this,
Log = XTrace.Log,
};
_container.AddSingleton(pm);
// プラグインを起動
WriteLog("プラグインを起動[{0}]", pm.Identity);
pm.Load();
pm.Init();
foreach (var item in pm.Plugins)
{
if (item is IAgentPlugin plugin)
{
try
{
plugin.Start();
}
catch (Exception ex)
{
XTrace.WriteException(ex);
}
}
}
管理クラス PluginManager は Load でプラグインをロードし、外部 DLL をスキャンすることをサポートします。次に Init でプラグインに初期化作業を通知します。最後に自分のビジネス操作を実行できます。星尘代理ではここで Start を呼び出します。
プラグインとは、実際には IPlugin インターフェースを実装するか、PluginAttribute 属性を追加したものです。以下のようになります。
/// <summary>星尘代理プラグイン</summary>
public interface IAgentPlugin : IPlugin
{
/// <summary>作業を開始</summary>
public void Start();
/// <summary>作業を停止</summary>
/// <param name="reason"></param>
public void Stop(String reason);
}
/// <summary>星尘代理プラグイン基底クラス</summary>
[Plugin("StarAgent")]
public abstract class AgentPlugin : DisposeBase, IAgentPlugin
{
/// <summary>サービスプロバイダー</summary>
public IServiceProvider? Provider { get; set; }
/// <summary>プラグインを初期化</summary>
/// <param name="identity"></param>
/// <param name="provider"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public virtual Boolean Init(String? identity, IServiceProvider provider)
{
if (identity != "StarAgent") return false;
Provider = provider;
return true;
}
/// <summary>作業を開始</summary>
public virtual void Start() { }
/// <summary>作業を停止</summary>
/// <param name="reason"></param>
public virtual void Stop(String reason) { }
}
コア原理#
汎用プラグインの実装は、一般的にインターフェースまたは属性です。
/// <summary>汎用プラグインインターフェース</summary>
/// <remarks>
/// 簡単な汎用プラグインシステムを構築するために、次のように規定します:
/// 1、プラグインをロードするホストは、プラグインをロードした後にプラグインのインスタンス化を行います。この時、プラグインのコンストラクタで何かを行うことができますが、ビジネス処理を開始すべきではありません。ホストの準備作業がまだ完了していない可能性があるためです。
/// 2、ホストがすべての準備を整えた後、プラグインのInitメソッドを順番に呼び出し、ホストの識別子を渡します。プラグインは識別子を通じて自分のターゲットホストかどうかを区別します。プラグインのInitはできるだけ早く完了するべきです。
/// 3、プラグインが<see cref="IDisposable"/>インターフェースを実装している場合、ホストは最後にリソースをクリーンアップします。
/// </remarks>
public interface IPlugin
{
/// <summary>初期化</summary>
/// <param name="identity">プラグインホスト識別子</param>
/// <param name="provider">サービスプロバイダー</param>
/// <returns>初期化が成功したかどうかを返します。現在のホストが期待されるホストでない場合、ここでfalseを返します。</returns>
Boolean Init(String? identity, IServiceProvider provider);
}
/// <summary>プラグイン属性。特定のプラグイン実装クラスが特定のホストをサポートしているかどうかを判断するために使用されます。</summary>
/// <remarks>インスタンス化</remarks>
/// <param name="identity"></param>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class PluginAttribute(String identity) : Attribute
{
/// <summary>プラグインホスト識別子</summary>
public String Identity { get; set; } = identity;
}
プラグインインターフェースは非常にシンプルで、Init のみがあります。複数のプラグインシステムが存在する可能性があるため、異なるタイプのプラグインを区別するために Identity を指定する必要があります。
サービスプロバイダー IServiceProvider も非常に重要で、プラグイン内部でさまざまなサービス実装を取得するのに便利です。
ご覧の通り、IPlugin インターフェースには Init 初期化のみがあり、破棄のインターフェースはありません。一般的に、プラグインの破棄を示すために IDispose を使用するため、IPlugin は再度そのようなメソッドを定義する必要はありません。
プラグインを管理するために、管理クラス PluginManager を導入します。
- Identity。現在のプラグイン識別子を指定し、その識別子のプラグインのみをロードします。例えば、前述の入門コードの StarAgent
- Provider。ホストのサービスプロバイダーで、プラグインは一般的に他のオブジェクトと相互作用する必要があるため、ここがつながりとなります。
- Plugins。プラグインのコレクションで、ロードされたプラグインを保管します。
- LoadPlugins。プラグインをスキャンし、プラグインのコレクションを迅速に取得できます。
- Load。プラグインをロードし、スキャン後に Plugins コレクションを変更します。
- Init。プラグインを初期化し、順次プラグインの Init インターフェースを呼び出します。