Plugin Lifecycle
Metadata:
- Title: Plugin Lifecycle - Discovery, Loading, and Management
- Status: draft
- Updated: 2024-09-28
- Author: ColorVision Development Team
简介
本文档详细描述 ColorVision 插件系统的完整生命周期,包括插件发现、装载、初始化、运行时管理、以及卸载过程。还涵盖了失败隔离机制和版本兼容性策略。
目录
插件系统概览
架构组件
核心接口
csharp
/// \<summary\>
/// 插件基础接口
/// </summary>
public interface IPlugin
{
/// \<summary\>插件唯一标识符</summary>
string Id { get; }
/// \<summary\>插件名称</summary>
string Name { get; }
/// \<summary\>插件版本</summary>
Version Version { get; }
/// \<summary\>插件描述</summary>
string Description { get; }
/// \<summary\>插件作者</summary>
string Author { get; }
/// \<summary\>初始化插件</summary>
Task InitializeAsync(IPluginContext context);
/// \<summary\>启动插件</summary>
Task StartAsync();
/// \<summary\>停止插件</summary>
Task StopAsync();
/// \<summary\>清理资源</summary>
Task ShutdownAsync();
}生命周期阶段
完整生命周期状态图
状态定义
csharp
public enum PluginState
{
/// \<summary\>未知状态</summary>
Unknown = 0,
/// \<summary\>已发现</summary>
Discovered = 1,
/// \<summary\>装载中</summary>
Loading = 2,
/// \<summary\>已装载</summary>
Loaded = 3,
/// \<summary\>装载失败</summary>
LoadFailed = 4,
/// \<summary\>初始化中</summary>
Initializing = 5,
/// \<summary\>已初始化</summary>
Initialized = 6,
/// \<summary\>初始化失败</summary>
InitFailed = 7,
/// \<summary\>启动中</summary>
Starting = 8,
/// \<summary\>运行中</summary>
Running = 9,
/// \<summary\>启动失败</summary>
StartFailed = 10,
/// \<summary\>停止中</summary>
Stopping = 11,
/// \<summary\>已停止</summary>
Stopped = 12,
/// \<summary\>运行异常</summary>
Error = 13,
/// \<summary\>卸载中</summary>
Unloading = 14,
/// \<summary\>已卸载</summary>
Unloaded = 15
}插件发现机制
发现策略
插件清单格式
json
{
"plugin": {
"id": "com.colorvision.plugin.example",
"name": "示例插件",
"version": "1.2.3",
"description": "这是一个示例插件",
"author": "ColorVision Team",
"website": "https://colorvision.com",
"license": "MIT",
"category": "Analysis",
"tags": ["image", "analysis", "opencv"],
"compatibility": {
"minHostVersion": "3.0.0",
"maxHostVersion": "4.0.0",
"targetFramework": "net8.0",
"architecture": ["x64", "x86"]
},
"dependencies": [
{
"id": "opencv",
"version": "4.5.0",
"required": true
}
],
"assembly": {
"fileName": "ExamplePlugin.dll",
"entryPoint": "ExamplePlugin.PluginEntry",
"configFile": "plugin.config"
},
"permissions": [
"system.io.file.read",
"system.io.file.write",
"device.camera.access"
],
"ui": {
"menuItems": [
{
"text": "示例功能",
"command": "example.action",
"icon": "icon.png",
"shortcut": "Ctrl+E"
}
],
"toolbarButtons": [
{
"text": "快速处理",
"command": "example.quickProcess",
"icon": "quick.png"
}
]
}
}
}发现器实现
csharp
public class PluginDiscoveryService : IPluginDiscoveryService
{
private readonly ILogger _logger;
private readonly PluginDiscoveryOptions _options;
public async Task\<IEnumerable\<PluginDescriptor>\> DiscoverPluginsAsync()
{
var plugins = new List\\<PluginDescriptor\>();
// 扫描本地插件目录
plugins.AddRange(await ScanLocalDirectoryAsync(_options.PluginDirectory));
// 从配置文件加载指定插件
plugins.AddRange(await LoadFromConfigAsync(_options.ConfigFile));
// 验证和过滤插件
return await ValidatePluginsAsync(plugins);
}
private async Task\<IEnumerable\<PluginDescriptor>\> ScanLocalDirectoryAsync(string directory)
{
var plugins = new List\\<PluginDescriptor\>();
if (!Directory.Exists(directory))
{
_logger.Warning("Plugin directory not found: {Directory}", directory);
return plugins;
}
var pluginFiles = Directory.GetFiles(directory, "*.dll", SearchOption.AllDirectories);
foreach (var file in pluginFiles)
{
try
{
var manifestFile = Path.Combine(Path.GetDirectoryName(file), "plugin.json");
if (File.Exists(manifestFile))
{
var manifest = await ParseManifestAsync(manifestFile);
var descriptor = CreateDescriptor(file, manifest);
plugins.Add(descriptor);
}
}
catch (Exception ex)
{
_logger.Error(ex, "Failed to process plugin file: {File}", file);
}
}
return plugins;
}
private async Task\<IEnumerable\<PluginDescriptor>\> ValidatePluginsAsync(
IEnumerable\<PluginDescriptor\> plugins)
{
var validPlugins = new List\\<PluginDescriptor\>();
foreach (var plugin in plugins)
{
try
{
// 验证文件完整性
if (!await ValidateFileIntegrityAsync(plugin.AssemblyPath))
continue;
// 检查数字签名
if (!await ValidateSignatureAsync(plugin.AssemblyPath))
continue;
// 检查兼容性
if (!ValidateCompatibility(plugin))
continue;
validPlugins.Add(plugin);
_logger.Information("Plugin validated: {PluginId}", plugin.Id);
}
catch (Exception ex)
{
_logger.Error(ex, "Plugin validation failed: {PluginId}", plugin.Id);
}
}
return validPlugins;
}
}装载与初始化
装载过程
程序集装载实现
csharp
public class PluginLoader : IPluginLoader
{
private readonly Dictionary\\<string, PluginLoadContext\> _loadContexts = new();
private readonly ILogger _logger;
public async Task\<IPlugin\> LoadPluginAsync(PluginDescriptor descriptor)
{
try
{
// 创建插件专用的加载上下文
var loadContext = new PluginLoadContext(descriptor.AssemblyPath, descriptor.Id);
_loadContexts[descriptor.Id] = loadContext;
// 加载主程序集
var assembly = loadContext.LoadFromAssemblyPath(descriptor.AssemblyPath);
// 查找插件入口点
var entryPointType = FindEntryPointType(assembly, descriptor);
if (entryPointType == null)
{
throw new PluginLoadException($"Entry point not found in plugin: {descriptor.Id}");
}
// 创建插件实例
var plugin = (IPlugin)Activator.CreateInstance(entryPointType);
// 验证插件接口
ValidatePluginInterface(plugin, descriptor);
_logger.Information("Plugin loaded successfully: {PluginId}", descriptor.Id);
return plugin;
}
catch (Exception ex)
{
_logger.Error(ex, "Failed to load plugin: {PluginId}", descriptor.Id);
throw;
}
}
private Type FindEntryPointType(Assembly assembly, PluginDescriptor descriptor)
{
// 首先尝试从清单指定的入口点
if (!string.IsNullOrEmpty(descriptor.EntryPoint))
{
var type = assembly.GetType(descriptor.EntryPoint);
if (type != null && typeof(IPlugin).IsAssignableFrom(type))
return type;
}
// 搜索实现了IPlugin接口的类型
var pluginTypes = assembly.GetTypes()
.Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract)
.ToArray();
if (pluginTypes.Length == 1)
return pluginTypes[0];
if (pluginTypes.Length > 1)
{
// 多个实现时,优先选择带有PluginAttribute的类型
var attributedType = pluginTypes
.FirstOrDefault(t => t.GetCustomAttribute\<PluginAttribute\>() != null);
return attributedType ?? pluginTypes[0];
}
return null;
}
}
/// \<summary\>
/// 插件专用程序集加载上下文
/// 提供插件隔离和卸载能力
/// </summary>
public class PluginLoadContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver _resolver;
private readonly string _pluginId;
public PluginLoadContext(string pluginPath, string pluginId) : base(pluginId, true)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
_pluginId = pluginId;
}
protected override Assembly Load(AssemblyName assemblyName)
{
var assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
return assemblyPath != null ? LoadFromAssemblyPath(assemblyPath) : null;
}
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
var libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
return libraryPath != null ? LoadUnmanagedDllFromPath(libraryPath) : IntPtr.Zero;
}
}插件初始化
csharp
public class PluginInitializer
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger _logger;
public async Task\<bool\> InitializePluginAsync(IPlugin plugin, PluginDescriptor descriptor)
{
try
{
// 创建插件上下文
var context = CreatePluginContext(plugin, descriptor);
// 验证权限
ValidatePermissions(descriptor.Permissions);
// 注入服务依赖
await InjectDependenciesAsync(plugin, context);
// 执行插件初始化
await plugin.InitializeAsync(context);
// 注册插件服务和扩展点
RegisterPluginServices(plugin, context);
// 集成UI元素
IntegrateUserInterface(plugin, descriptor);
_logger.Information("Plugin initialized: {PluginId}", plugin.Id);
return true;
}
catch (Exception ex)
{
_logger.Error(ex, "Plugin initialization failed: {PluginId}", plugin.Id);
return false;
}
}
private IPluginContext CreatePluginContext(IPlugin plugin, PluginDescriptor descriptor)
{
return new PluginContext
{
Plugin = plugin,
Descriptor = descriptor,
ServiceProvider = _serviceProvider,
Logger = _logger.ForContext("PluginId", plugin.Id),
Configuration = LoadPluginConfiguration(descriptor),
DataDirectory = GetPluginDataDirectory(plugin.Id),
TempDirectory = GetPluginTempDirectory(plugin.Id)
};
}
private void IntegrateUserInterface(IPlugin plugin, PluginDescriptor descriptor)
{
// 集成菜单项
foreach (var menuItem in descriptor.Manifest.UI?.MenuItems ?? [])
{
RegisterMenuItem(plugin, menuItem);
}
// 集成工具栏按钮
foreach (var button in descriptor.Manifest.UI?.ToolbarButtons ?? [])
{
RegisterToolbarButton(plugin, button);
}
// 集成快捷键
foreach (var shortcut in descriptor.Manifest.UI?.Shortcuts ?? [])
{
RegisterShortcut(plugin, shortcut);
}
}
}运行时管理
插件宿主实现
csharp
public class PluginHost : IPluginHost
{
private readonly ConcurrentDictionary\\<string, PluginRuntime\> _runningPlugins = new();
private readonly IEventBus _eventBus;
private readonly ILogger _logger;
public async Task StartPluginAsync(string pluginId)
{
if (!_runningPlugins.TryGetValue(pluginId, out var runtime))
{
throw new InvalidOperationException($"Plugin not found: {pluginId}");
}
try
{
await runtime.Plugin.StartAsync();
runtime.State = PluginState.Running;
runtime.StartTime = DateTime.UtcNow;
// 发布插件启动事件
await _eventBus.PublishAsync(new PluginStartedEvent
{
PluginId = pluginId,
StartTime = runtime.StartTime.Value
});
_logger.Information("Plugin started: {PluginId}", pluginId);
}
catch (Exception ex)
{
runtime.State = PluginState.StartFailed;
runtime.LastError = ex.Message;
_logger.Error(ex, "Failed to start plugin: {PluginId}", pluginId);
throw;
}
}
public async Task StopPluginAsync(string pluginId)
{
if (!_runningPlugins.TryGetValue(pluginId, out var runtime))
return;
try
{
runtime.State = PluginState.Stopping;
await runtime.Plugin.StopAsync();
runtime.State = PluginState.Stopped;
await _eventBus.PublishAsync(new PluginStoppedEvent
{
PluginId = pluginId,
StopTime = DateTime.UtcNow
});
}
catch (Exception ex)
{
runtime.State = PluginState.Error;
runtime.LastError = ex.Message;
_logger.Error(ex, "Failed to stop plugin: {PluginId}", pluginId);
}
}
}
public class PluginRuntime
{
public IPlugin Plugin { get; set; }
public PluginDescriptor Descriptor { get; set; }
public PluginState State { get; set; }
public DateTime LoadTime { get; set; }
public DateTime? StartTime { get; set; }
public string LastError { get; set; }
public PluginMetrics Metrics { get; set; }
}失败隔离机制
隔离策略
异常处理实现
csharp
public class PluginFailureHandler : IPluginFailureHandler
{
private readonly PluginRestartPolicy _restartPolicy;
private readonly ILogger _logger;
public async Task HandlePluginFailureAsync(string pluginId, Exception exception)
{
var runtime = GetPluginRuntime(pluginId);
if (runtime == null) return;
// 记录异常信息
_logger.Error(exception, "Plugin failure: {PluginId}", pluginId);
// 更新插件状态
runtime.State = PluginState.Error;
runtime.LastError = exception.Message;
runtime.Metrics.FailureCount++;
// 确定恢复策略
var strategy = DetermineRecoveryStrategy(runtime, exception);
switch (strategy)
{
case RecoveryStrategy.Restart:
await RestartPluginAsync(pluginId);
break;
case RecoveryStrategy.FallbackMode:
await EnableFallbackModeAsync(pluginId);
break;
case RecoveryStrategy.Disable:
await DisablePluginAsync(pluginId);
break;
case RecoveryStrategy.Isolate:
await IsolatePluginAsync(pluginId);
break;
}
// 通知用户
await NotifyUserAsync(pluginId, strategy, exception);
}
private RecoveryStrategy DetermineRecoveryStrategy(PluginRuntime runtime, Exception exception)
{
// 检查重启次数限制
if (runtime.Metrics.RestartCount >= _restartPolicy.MaxRestartCount)
{
return RecoveryStrategy.Disable;
}
// 根据异常类型决定策略
return exception switch
{
OutOfMemoryException => RecoveryStrategy.Restart,
TimeoutException => RecoveryStrategy.Restart,
SecurityException => RecoveryStrategy.Isolate,
FileNotFoundException => RecoveryStrategy.FallbackMode,
UnauthorizedAccessException => RecoveryStrategy.Disable,
_ => RecoveryStrategy.Restart
};
}
private async Task RestartPluginAsync(string pluginId)
{
var runtime = GetPluginRuntime(pluginId);
runtime.Metrics.RestartCount++;
try
{
// 停止插件
await StopPluginSafelyAsync(pluginId);
// 等待冷却时间
await Task.Delay(_restartPolicy.RestartDelay);
// 重新启动
await StartPluginAsync(pluginId);
_logger.Information("Plugin restarted successfully: {PluginId}", pluginId);
}
catch (Exception ex)
{
_logger.Error(ex, "Failed to restart plugin: {PluginId}", pluginId);
await DisablePluginAsync(pluginId);
}
}
}版本兼容策略
版本管理
兼容性检查实现
csharp
public class PluginCompatibilityChecker : IPluginCompatibilityChecker
{
private readonly HostVersionInfo _hostVersion;
public CompatibilityResult CheckCompatibility(PluginDescriptor plugin)
{
var result = new CompatibilityResult { IsCompatible = true };
// 检查宿主版本兼容性
CheckHostVersionCompatibility(plugin, result);
// 检查.NET运行时兼容性
CheckRuntimeCompatibility(plugin, result);
// 检查架构兼容性
CheckArchitectureCompatibility(plugin, result);
// 检查API版本兼容性
CheckApiCompatibility(plugin, result);
// 检查依赖项兼容性
CheckDependencyCompatibility(plugin, result);
return result;
}
private void CheckHostVersionCompatibility(PluginDescriptor plugin, CompatibilityResult result)
{
var compatibility = plugin.Manifest.Compatibility;
if (compatibility.MinHostVersion != null)
{
if (_hostVersion.Version < Version.Parse(compatibility.MinHostVersion))
{
result.IsCompatible = false;
result.Issues.Add(new CompatibilityIssue
{
Type = IssueType.HostVersionTooLow,
Message = $"需要宿主版本 >= {compatibility.MinHostVersion},当前版本 {_hostVersion.Version}"
});
}
}
if (compatibility.MaxHostVersion != null)
{
if (_hostVersion.Version > Version.Parse(compatibility.MaxHostVersion))
{
result.IsCompatible = false;
result.Issues.Add(new CompatibilityIssue
{
Type = IssueType.HostVersionTooHigh,
Message = $"需要宿主版本 <= {compatibility.MaxHostVersion},当前版本 {_hostVersion.Version}"
});
}
}
}
}卸载与清理
卸载过程
资源清理实现
csharp
public class PluginUnloader : IPluginUnloader
{
public async Task\<bool\> UnloadPluginAsync(string pluginId)
{
try
{
var runtime = GetPluginRuntime(pluginId);
if (runtime == null) return false;
// 1. 停止插件
if (runtime.State == PluginState.Running)
{
await runtime.Plugin.StopAsync();
}
// 2. 清理插件资源
await runtime.Plugin.ShutdownAsync();
// 3. 移除UI集成
RemoveUserInterfaceElements(pluginId);
// 4. 取消事件订阅
UnsubscribeEvents(pluginId);
// 5. 清理服务注册
UnregisterServices(pluginId);
// 6. 清理临时文件
CleanupTempFiles(runtime.TempDirectory);
// 7. 卸载程序集
UnloadAssembly(pluginId);
// 8. 移除运行时记录
RemovePluginRuntime(pluginId);
_logger.Information("Plugin unloaded successfully: {PluginId}", pluginId);
return true;
}
catch (Exception ex)
{
_logger.Error(ex, "Failed to unload plugin: {PluginId}", pluginId);
return false;
}
}
private void UnloadAssembly(string pluginId)
{
if (_loadContexts.TryRemove(pluginId, out var loadContext))
{
// 卸载程序集上下文
loadContext.Unload();
// 等待垃圾回收
for (int i = 0; i < 10 && loadContext.IsCollectible; i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(100);
}
if (loadContext.IsCollectible)
{
_logger.Warning("Plugin assembly may not be fully unloaded: {PluginId}", pluginId);
}
}
}
private void CleanupTempFiles(string tempDirectory)
{
try
{
if (Directory.Exists(tempDirectory))
{
Directory.Delete(tempDirectory, true);
}
}
catch (Exception ex)
{
_logger.Warning(ex, "Failed to cleanup temp directory: {Directory}", tempDirectory);
}
}
}完整的插件管理器
csharp
public class PluginManager : IPluginManager, IDisposable
{
private readonly IPluginDiscoveryService _discoveryService;
private readonly IPluginLoader _loader;
private readonly IPluginHost _host;
private readonly IPluginUnloader _unloader;
private readonly ConcurrentDictionary\\<string, PluginRuntime\> _plugins = new();
public async Task LoadAllPluginsAsync()
{
// 发现插件
var descriptors = await _discoveryService.DiscoverPluginsAsync();
// 按依赖顺序排序
var sortedDescriptors = TopologicalSort(descriptors);
// 逐个加载插件
foreach (var descriptor in sortedDescriptors)
{
try
{
await LoadPluginAsync(descriptor);
}
catch (Exception ex)
{
_logger.Error(ex, "Failed to load plugin: {PluginId}", descriptor.Id);
}
}
}
public async Task\<bool\> LoadPluginAsync(PluginDescriptor descriptor)
{
try
{
// 装载插件
var plugin = await _loader.LoadPluginAsync(descriptor);
// 创建运行时
var runtime = new PluginRuntime
{
Plugin = plugin,
Descriptor = descriptor,
State = PluginState.Loaded,
LoadTime = DateTime.UtcNow,
Metrics = new PluginMetrics()
};
_plugins[descriptor.Id] = runtime;
// 初始化插件
await InitializePluginAsync(plugin, descriptor);
return true;
}
catch (Exception ex)
{
_logger.Error(ex, "Plugin loading failed: {PluginId}", descriptor.Id);
return false;
}
}
public void Dispose()
{
// 卸载所有插件
foreach (var pluginId in _plugins.Keys.ToArray())
{
try
{
_unloader.UnloadPluginAsync(pluginId).Wait();
}
catch (Exception ex)
{
_logger.Error(ex, "Error during plugin cleanup: {PluginId}", pluginId);
}
}
}
}最后更新: 2024-09-28 | 状态: draft
