wsf

wsf

插件框架IPlugin

插件框架 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 接口
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。