插件式架构:解耦与扩展的艺术与实践
🤔 什么是插件式开发?
插件式开发(Plugin-based Development)是一种软件架构模式,它允许应用程序在运行时动态加载、卸载和执行扩展功能模块,而无需修改主程序的核心代码。这种架构将应用程序的核心功能与可扩展功能分离,通过定义良好的接口契约实现模块间的松耦合。
插件式开发的核心概念
插件(Plugin):一个独立的、可替换的软件模块,实现了特定的接口契约,用于扩展宿主应用程序的功能。
宿主程序(Host):包含核心功能的主应用程序,负责发现、加载、管理和执行插件。
契约(Contract):插件与宿主程序之间交互的接口定义,确保双方能够正确通信。
插件式架构的历史演变
插件式架构并非新鲜概念,其思想可以追溯到几十年前的操作系统设计。现代插件系统的典型代表包括:
- Eclipse IDE - 完全基于插件的开发环境
- Visual Studio Code - 通过扩展机制提供丰富功能
- Photoshop - 支持滤镜、脚本等插件扩展
- Web浏览器 - 通过插件/扩展增强功能
- 游戏引擎 - 如Unity、Unreal Engine的插件系统
现代插件系统的特征
- 动态性:插件可以在运行时加载和卸载
- 隔离性:插件错误不应导致宿主程序崩溃
- 版本兼容性:支持不同版本插件的共存
- 安全性:插件应运行在受限环境中,防止恶意行为
- 发现机制:宿主程序能够自动发现可用插件
🧩 为何选择插件式开发?------ 解耦与扩展的艺术
1. 高度解耦:模块化设计的极致体现
代码耦合度分析:
csharp
// 紧耦合的代码示例 - 不推荐
public class ReportGenerator
{
private PdfExporter _pdfExporter = new PdfExporter();
private ExcelExporter _excelExporter = new ExcelExporter();
public void GenerateReport(string format, Data data)
{
if (format == "PDF")
_pdfExporter.Export(data);
else if (format == "Excel")
_excelExporter.Export(data);
// 每添加一个新格式,都需要修改这个类
}
}
// 使用插件架构的解耦实现
public interface IExportPlugin
{
string Format { get; }
void Export(Data data);
}
public class ReportGenerator
{
private List<IExportPlugin> _plugins = new List<IExportPlugin>();
public void RegisterPlugin(IExportPlugin plugin)
{
_plugins.Add(plugin);
}
public void GenerateReport(string format, Data data)
{
var plugin = _plugins.FirstOrDefault(p => p.Format == format);
plugin?.Export(data);
}
}
解耦带来的好处:
- 独立开发:不同团队可以并行开发不同插件
- 独立测试:每个插件可以单独进行单元测试
- 独立部署:插件可以单独更新,不影响主程序
- 技术异构:不同插件可以使用不同的技术栈
2. 极致的扩展性:应对需求变化的利器
扩展性设计模式:
csharp
// 策略模式在插件系统中的应用
public interface ISortStrategy
{
void Sort(List<int> data);
}
public class QuickSortPlugin : ISortStrategy
{
public void Sort(List<int> data)
{
// 快速排序实现
QuickSort(data, 0, data.Count - 1);
}
private void QuickSort(List<int> arr, int low, int high)
{
if (low < high)
{
int pi = Partition(arr, low, high);
QuickSort(arr, low, pi - 1);
QuickSort(arr, pi + 1, high);
}
}
private int Partition(List<int> arr, int low, int high)
{
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++)
{
if (arr[j] < pivot)
{
i++;
(arr[i], arr[j]) = (arr[j], arr[i]);
}
}
(arr[i + 1], arr[high]) = (arr[high], arr[i + 1]);
return i + 1;
}
}
public class MergeSortPlugin : ISortStrategy
{
public void Sort(List<int> data)
{
// 归并排序实现
if (data.Count <= 1) return;
int mid = data.Count / 2;
List<int> left = data.GetRange(0, mid);
List<int> right = data.GetRange(mid, data.Count - mid);
Sort(left);
Sort(right);
Merge(data, left, right);
}
private void Merge(List<int> result, List<int> left, List<int> right)
{
int i = 0, j = 0, k = 0;
while (i < left.Count && j < right.Count)
{
if (left[i] <= right[j])
result[k++] = left[i++];
else
result[k++] = right[j++];
}
while (i < left.Count) result[k++] = left[i++];
while (j < right.Count) result[k++] = right[j++];
}
}
3. 增强可维护性:长期项目的守护者
维护性指标:
- 圈复杂度降低:每个插件专注于单一职责
- 代码重复减少:通用功能可以提取为共享插件
- 变更影响分析简化:修改插件只影响局部功能
- 技术债务管理:可以逐步替换老旧的插件
版本管理示例:
csharp
// 插件版本管理
[AttributeUsage(AttributeTargets.Class)]
public class PluginMetadataAttribute : Attribute
{
public string Name { get; }
public Version Version { get; }
public string Author { get; }
public string Description { get; }
public PluginMetadataAttribute(string name, string version,
string author = "", string description = "")
{
Name = name;
Version = new Version(version);
Author = author;
Description = description;
}
}
// 插件接口支持版本
public interface IPlugin
{
Version ApiVersion { get; }
string Name { get; }
void Initialize();
void Execute();
void Cleanup();
}
// 使用版本控制的插件加载器
public class VersionAwarePluginLoader
{
private readonly Dictionary<Version, List<IPlugin>> _pluginsByVersion
= new Dictionary<Version, List<IPlugin>>();
public void LoadPlugin(IPlugin plugin)
{
if (!_pluginsByVersion.ContainsKey(plugin.ApiVersion))
_pluginsByVersion[plugin.ApiVersion] = new List<IPlugin>();
_pluginsByVersion[plugin.ApiVersion].Add(plugin);
plugin.Initialize();
}
public void ExecutePlugins(Version minVersion)
{
var compatiblePlugins = _pluginsByVersion
.Where(kv => kv.Key >= minVersion)
.SelectMany(kv => kv.Value);
foreach (var plugin in compatiblePlugins)
{
try
{
plugin.Execute();
}
catch (Exception ex)
{
// 优雅处理插件异常
LogError($"Plugin {plugin.Name} failed: {ex.Message}");
}
}
}
}
4. 支持动态加载与卸载:灵活性的终极体现
动态生命周期管理:
csharp
// 支持热插拔的插件管理器
public class HotSwapPluginManager : IDisposable
{
private readonly string _pluginsDirectory;
private readonly Dictionary<string, PluginContext> _loadedPlugins;
private FileSystemWatcher _fileWatcher;
public HotSwapPluginManager(string pluginsDirectory)
{
_pluginsDirectory = pluginsDirectory;
_loadedPlugins = new Dictionary<string, PluginContext>();
// 监视插件目录变化
_fileWatcher = new FileSystemWatcher(pluginsDirectory, "*.dll")
{
EnableRaisingEvents = true,
IncludeSubdirectories = false
};
_fileWatcher.Created += OnPluginFileCreated;
_fileWatcher.Deleted += OnPluginFileDeleted;
_fileWatcher.Changed += OnPluginFileChanged;
}
private class PluginContext
{
public Assembly Assembly { get; set; }
public IPlugin PluginInstance { get; set; }
public DateTime LastLoadTime { get; set; }
public AppDomain AppDomain { get; set; }
}
private void OnPluginFileCreated(object sender, FileSystemEventArgs e)
{
// 延迟加载,避免文件锁定
Task.Delay(1000).ContinueWith(_ => LoadPlugin(e.FullPath));
}
private void OnPluginFileDeleted(object sender, FileSystemEventArgs e)
{
var pluginName = Path.GetFileNameWithoutExtension(e.Name);
if (_loadedPlugins.ContainsKey(pluginName))
{
UnloadPlugin(pluginName);
}
}
private void OnPluginFileChanged(object sender, FileSystemEventArgs e)
{
// 热重载:先卸载再重新加载
var pluginName = Path.GetFileNameWithoutExtension(e.Name);
if (_loadedPlugins.ContainsKey(pluginName))
{
UnloadPlugin(pluginName);
Task.Delay(1000).ContinueWith(_ => LoadPlugin(e.FullPath));
}
}
public void LoadPlugin(string pluginPath)
{
try
{
// 在独立AppDomain中加载插件,实现完全隔离
var setup = new AppDomainSetup
{
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
PrivateBinPath = Path.GetDirectoryName(pluginPath)
};
var appDomain = AppDomain.CreateDomain(
$"PluginDomain_{Path.GetFileNameWithoutExtension(pluginPath)}",
null, setup);
var loader = (PluginLoaderProxy)appDomain.CreateInstanceAndUnwrap(
typeof(PluginLoaderProxy).Assembly.FullName,
typeof(PluginLoaderProxy).FullName);
var plugin = loader.LoadPlugin(pluginPath);
var context = new PluginContext
{
Assembly = plugin.GetType().Assembly,
PluginInstance = plugin,
LastLoadTime = DateTime.Now,
AppDomain = appDomain
};
_loadedPlugins[plugin.Name] = context;
plugin.Initialize();
Console.WriteLine($"Plugin {plugin.Name} loaded successfully.");
}
catch (Exception ex)
{
Console.WriteLine($"Failed to load plugin {pluginPath}: {ex.Message}");
}
}
public void UnloadPlugin(string pluginName)
{
if (_loadedPlugins.TryGetValue(pluginName, out var context))
{
try
{
context.PluginInstance.Cleanup();
AppDomain.Unload(context.AppDomain);
_loadedPlugins.Remove(pluginName);
Console.WriteLine($"Plugin {pluginName} unloaded successfully.");
}
catch (Exception ex)
{
Console.WriteLine($"Failed to unload plugin {pluginName}: {ex.Message}");
}
}
}
// 代理类,用于跨AppDomain通信
[Serializable]
public class PluginLoaderProxy : MarshalByRefObject
{
public IPlugin LoadPlugin(string assemblyPath)
{
var assembly = Assembly.LoadFrom(assemblyPath);
foreach (var type in assembly.GetExportedTypes())
{
if (typeof(IPlugin).IsAssignableFrom(type) && !type.IsAbstract)
{
return (IPlugin)Activator.CreateInstance(type);
}
}
throw new InvalidOperationException("No IPlugin implementation found.");
}
}
public void Dispose()
{
_fileWatcher?.Dispose();
// 清理所有插件
foreach (var pluginName in _loadedPlugins.Keys.ToList())
{
UnloadPlugin(pluginName);
}
}
}
🏗️ 插件系统的核心架构
插件系统架构图
┌─────────────────────────────────────────────────────┐
│ 宿主应用程序(Host) │
├─────────────────────────────────────────────────────┤
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 插件管理器 │ │ 配置管理器 │ │ 生命周期管理 │ │
│ └────────────┘ └────────────┘ └────────────┘ │
├─────────────────────────────────────────────────────┤
│ 插件接口层(Contracts/Interfaces) │
├─────────────────────────────────────────────────────┤
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 插件A │ │ 插件B │ │ 插件C │ │
│ │ (DLL/SO) │ │ (DLL/SO) │ │ (DLL/SO) │ │
│ └────────────┘ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────┘
关键组件设计
1. 插件发现机制
csharp
// 基于反射的插件发现
public class PluginDiscoveryService
{
private readonly List<IPlugin> _plugins = new List<IPlugin>();
private readonly List<PluginMetadata> _metadata = new List<PluginMetadata>();
public void DiscoverPlugins(string directory)
{
var dllFiles = Directory.GetFiles(directory, "*.dll");
foreach (var dll in dllFiles)
{
try
{
var assembly = Assembly.LoadFrom(dll);
DiscoverPluginsInAssembly(assembly);
}
catch (Exception ex)
{
LogWarning($"Failed to load assembly {dll}: {ex.Message}");
}
}
}
private void DiscoverPluginsInAssembly(Assembly assembly)
{
foreach (var type in assembly.GetTypes())
{
// 检查是否实现了IPlugin接口
if (typeof(IPlugin).IsAssignableFrom(type) &&
!type.IsAbstract &&
type.IsClass)
{
// 检查是否有插件元数据
var metadataAttr = type.GetCustomAttribute<PluginMetadataAttribute>();
var metadata = new PluginMetadata
{
Type = type,
Name = metadataAttr?.Name ?? type.Name,
Version = metadataAttr?.Version ?? new Version(1, 0),
Author = metadataAttr?.Author ?? "Unknown",
Description = metadataAttr?.Description ?? string.Empty,
Assembly = assembly
};
_metadata.Add(metadata);
}
}
}
public IPlugin InstantiatePlugin(PluginMetadata metadata)
{
try
{
var plugin = (IPlugin)Activator.CreateInstance(metadata.Type);
_plugins.Add(plugin);
return plugin;
}
catch (Exception ex)
{
throw new PluginInstantiationException(
$"Failed to instantiate plugin {metadata.Name}", ex);
}
}
public IEnumerable<PluginMetadata> GetAvailablePlugins()
{
return _metadata.AsReadOnly();
}
public IEnumerable<IPlugin> GetLoadedPlugins()
{
return _plugins.AsReadOnly();
}
}
// 插件依赖关系解析
public class PluginDependencyResolver
{
public class DependencyGraph
{
public Dictionary<string, List<string>> Dependencies { get; } = new();
public Dictionary<string, List<string>> Dependents { get; } = new();
}
public DependencyGraph BuildDependencyGraph(IEnumerable<PluginMetadata> plugins)
{
var graph = new DependencyGraph();
foreach (var plugin in plugins)
{
var deps = GetPluginDependencies(plugin);
graph.Dependencies[plugin.Name] = deps;
// 更新反向依赖
foreach (var dep in deps)
{
if (!graph.Dependents.ContainsKey(dep))
graph.Dependents[dep] = new List<string>();
graph.Dependents[dep].Add(plugin.Name);
}
}
return graph;
}
public List<string> GetLoadOrder(DependencyGraph graph)
{
var loadOrder = new List<string>();
var visited = new HashSet<string>();
var tempMarks = new HashSet<string>();
foreach (var plugin in graph.Dependencies.Keys)
{
if (!visited.Contains(plugin))
{
Visit(plugin, graph, visited, tempMarks, loadOrder);
}
}
return loadOrder;
}
private void Visit(string plugin, DependencyGraph graph,
HashSet<string> visited, HashSet<string> tempMarks,
List<string> loadOrder)
{
if (tempMarks.Contains(plugin))
throw new CircularDependencyException($"Circular dependency detected involving {plugin}");
if (!visited.Contains(plugin))
{
tempMarks.Add(plugin);
if (graph.Dependencies.ContainsKey(plugin))
{
foreach (var dependency in graph.Dependencies[plugin])
{
Visit(dependency, graph, visited, tempMarks, loadOrder);
}
}
tempMarks.Remove(plugin);
visited.Add(plugin);
loadOrder.Add(plugin);
}
}
private List<string> GetPluginDependencies(PluginMetadata plugin)
{
// 从插件元数据或特性中获取依赖信息
var deps = new List<string>();
var depsAttr = plugin.Type.GetCustomAttribute<PluginDependenciesAttribute>();
if (depsAttr != null)
{
deps.AddRange(depsAttr.RequiredPlugins);
}
return deps;
}
}
2. 插件生命周期管理
csharp
// 完整的插件生命周期管理器
public class PluginLifecycleManager : IDisposable
{
public enum PluginState
{
NotLoaded,
Loading,
Loaded,
Initializing,
Initialized,
Executing,
Error,
Unloading,
Unloaded
}
public class PluginContext
{
public IPlugin Plugin { get; set; }
public PluginMetadata Metadata { get; set; }
public PluginState State { get; set; }
public DateTime LoadTime { get; set; }
public Exception LastError { get; set; }
public PerformanceMetrics Metrics { get; set; }
public List<string> Dependencies { get; set; }
public List<string> Dependents { get; set; }
}
public class PerformanceMetrics
{
public TimeSpan LoadTime { get; set; }
public TimeSpan InitializeTime { get; set; }
public TimeSpan AverageExecutionTime { get; set; }
public int ExecutionCount { get; set; }
public DateTime LastExecution { get; set; }
}
private readonly Dictionary<string, PluginContext> _plugins;
private readonly IPluginDiscoveryService _discoveryService;
private readonly PluginDependencyResolver _dependencyResolver;
private readonly object _lock = new object();
public PluginLifecycleManager(string pluginsDirectory)
{
_plugins = new Dictionary<string, PluginContext>();
_discoveryService = new PluginDiscoveryService();
_dependencyResolver = new PluginDependencyResolver();
InitializePluginSystem(pluginsDirectory);
}
private void InitializePluginSystem(string pluginsDirectory)
{
// 发现所有可用插件
_discoveryService.DiscoverPlugins(pluginsDirectory);
// 构建依赖图
var availablePlugins = _discoveryService.GetAvailablePlugins().ToList();
var dependencyGraph = _dependencyResolver.BuildDependencyGraph(availablePlugins);
// 获取加载顺序
var loadOrder = _dependencyResolver.GetLoadOrder(dependencyGraph);
// 按顺序初始化上下文
foreach (var pluginName in loadOrder)
{
var metadata = availablePlugins.First(p => p.Name == pluginName);
var context = new PluginContext
{
Metadata = metadata,
State = PluginState.NotLoaded,
Dependencies = dependencyGraph.Dependencies.ContainsKey(pluginName)
? dependencyGraph.Dependencies[pluginName]
: new List<string>(),
Dependents = dependencyGraph.Dependents.ContainsKey(pluginName)
? dependencyGraph.Dependents[pluginName]
: new List<string>(),
Metrics = new PerformanceMetrics()
};
_plugins[pluginName] = context;
}
}
public async Task LoadPluginAsync(string pluginName)
{
lock (_lock)
{
if (!_plugins.ContainsKey(pluginName))
throw new PluginNotFoundException($"Plugin {pluginName} not found");
var context = _plugins[pluginName];
if (context.State != PluginState.NotLoaded &&
context.State != PluginState.Error)
throw new InvalidOperationException($"Plugin is in {context.State} state");
context.State = PluginState.Loading;
}
try
{
// 加载依赖
await LoadDependenciesAsync(pluginName);
// 加载插件本身
var context = _plugins[pluginName];
var stopwatch = Stopwatch.StartNew();
context.Plugin = _discoveryService.InstantiatePlugin(context.Metadata);
context.State = PluginState.Loaded;
context.LoadTime = DateTime.Now;
context.Metrics.LoadTime = stopwatch.Elapsed;
// 初始化插件
await InitializePluginAsync(pluginName);
LogInfo($"Plugin {pluginName} loaded and initialized successfully");
}
catch (Exception ex)
{
_plugins[pluginName].State = PluginState.Error;
_plugins[pluginName].LastError = ex;
throw new PluginLoadException($"Failed to load plugin {pluginName}", ex);
}
}
private async Task LoadDependenciesAsync(string pluginName)
{
var context = _plugins[pluginName];
foreach (var dependency in context.Dependencies)
{
if (_plugins.TryGetValue(dependency, out var depContext))
{
if (depContext.State != PluginState.Initialized)
{
await LoadPluginAsync(dependency);
}
}
else
{
throw new DependencyNotFoundException(
$"Dependency {dependency} not found for plugin {pluginName}");
}
}
}
private async Task InitializePluginAsync(string pluginName)
{
var context = _plugins[pluginName];
context.State = PluginState.Initializing;
try
{
var stopwatch = Stopwatch.StartNew();
if (context.Plugin is IAsyncInitializable asyncPlugin)
{
await asyncPlugin.InitializeAsync();
}
else
{
context.Plugin.Initialize();
}
context.State = PluginState.Initialized;
context.Metrics.InitializeTime = stopwatch.Elapsed;
}
catch (Exception ex)
{
context.State = PluginState.Error;
context.LastError = ex;
throw;
}
}
public async Task ExecutePluginAsync(string pluginName, object parameters = null)
{
var context = _plugins[pluginName];
if (context.State != PluginState.Initialized)
throw new InvalidOperationException($"Plugin is in {context.State} state");
context.State = PluginState.Executing;
try
{
var stopwatch = Stopwatch.StartNew();
if (context.Plugin is IAsyncPlugin asyncPlugin)
{
await asyncPlugin.ExecuteAsync(parameters);
}
else
{
context.Plugin.Execute();
}
// 更新性能指标
context.Metrics.ExecutionCount++;
context.Metrics.LastExecution = DateTime.Now;
context.Metrics.AverageExecutionTime = TimeSpan.FromTicks(
(context.Metrics.AverageExecutionTime.Ticks * (context.Metrics.ExecutionCount - 1)
+ stopwatch.Elapsed.Ticks) / context.Metrics.ExecutionCount);
context.State = PluginState.Initialized;
}
catch (Exception ex)
{
context.State = PluginState.Error;
context.LastError = ex;
throw new PluginExecutionException(
$"Plugin {pluginName} execution failed", ex);
}
}
public void Dispose()
{
// 按依赖关系的逆序卸载所有插件
var unloadOrder = _plugins.Keys
.OrderByDescending(name => _plugins[name].Dependents.Count)
.ToList();
foreach (var pluginName in unloadOrder)
{
if (_plugins[pluginName].State == PluginState.Initialized)
{
UnloadPlugin(pluginName);
}
}
}
}
3. 插件通信机制
csharp
// 插件间通信系统
public class PluginCommunicationBus
{
public interface IPluginMessage
{
string Source { get; }
string MessageType { get; }
DateTime Timestamp { get; }
}
public abstract class PluginMessage : IPluginMessage
{
public string Source { get; }
public string MessageType { get; }
public DateTime Timestamp { get; }
protected PluginMessage(string source, string messageType)
{
Source = source;
MessageType = messageType;
Timestamp = DateTime.UtcNow;
}
}
public class EventMessage : PluginMessage
{
public string EventName { get; }
public Dictionary<string, object> Data { get; }
public EventMessage(string source, string eventName,
Dictionary<string, object> data = null)
: base(source, "Event")
{
EventName = eventName;
Data = data ?? new Dictionary<string, object>();
}
}
public class RequestMessage : PluginMessage
{
public string RequestId { get; }
public string Method { get; }
public object[] Parameters { get; }
public RequestMessage(string source, string method,
object[] parameters, string requestId = null)
: base(source, "Request")
{
Method = method;
Parameters = parameters;
RequestId = requestId ?? Guid.NewGuid().ToString();
}
}
public class ResponseMessage : PluginMessage
{
public string RequestId { get; }
public object Result { get; }
public Exception Error { get; }
public ResponseMessage(string source, string requestId,
object result = null, Exception error = null)
: base(source, "Response")
{
RequestId = requestId;
Result = result;
Error = error;
}
}
// 消息处理器
public delegate Task MessageHandler<T>(T message) where T : IPluginMessage;
private readonly Dictionary<string, List<Delegate>> _handlers;
private readonly Dictionary<string, TaskCompletionSource<object>> _pendingRequests;
private readonly IPluginLifecycleManager _lifecycleManager;
public PluginCommunicationBus(IPluginLifecycleManager lifecycleManager)
{
_handlers = new Dictionary<string, List<Delegate>>();
_pendingRequests = new Dictionary<string, TaskCompletionSource<object>>();
_lifecycleManager = lifecycleManager;
}
public void Subscribe<T>(string messageType, MessageHandler<T> handler)
where T : IPluginMessage
{
if (!_handlers.ContainsKey(messageType))
_handlers[messageType] = new List<Delegate>();
_handlers[messageType].Add(handler);
}
public void Unsubscribe<T>(string messageType, MessageHandler<T> handler)
where T : IPluginMessage
{
if (_handlers.ContainsKey(messageType))
{
_handlers[messageType].Remove(handler);
}
}
public async Task PublishAsync(IPluginMessage message)
{
var messageType = message.MessageType;
if (_handlers.ContainsKey(messageType))
{
var tasks = new List<Task>();
foreach (var handler in _handlers[messageType])
{
try
{
// 动态调用处理程序
var task = (Task)handler.DynamicInvoke(message);
tasks.Add(task);
}
catch (Exception ex)
{
LogError($"Error in message handler: {ex.Message}");
}
}
await Task.WhenAll(tasks);
}
// 特殊处理响应消息
if (message is ResponseMessage response &&
_pendingRequests.TryGetValue(response.RequestId, out var tcs))
{
if (response.Error != null)
tcs.TrySetException(response.Error);
else
tcs.TrySetResult(response.Result);
}
}
public async Task<T> RequestAsync<T>(string targetPlugin, string method,
object[] parameters,
TimeSpan timeout = default)
{
var requestId = Guid.NewGuid().ToString();
var request = new RequestMessage(targetPlugin, method, parameters, requestId);
var tcs = new TaskCompletionSource<object>();
_pendingRequests[requestId] = tcs;
// 设置超时
var timeoutTask = Task.Delay(timeout == default ? TimeSpan.FromSeconds(30) : timeout)
.ContinueWith(_ =>
new TimeoutException($"Request to {targetPlugin}.{method} timed out"));
try
{
await PublishAsync(request);
var completedTask = await Task.WhenAny(tcs.Task, timeoutTask);
if (completedTask == timeoutTask)
throw await timeoutTask;
var result = await tcs.Task;
if (result is T typedResult)
return typedResult;
throw new InvalidCastException($"Cannot cast result to {typeof(T).Name}");
}
finally
{
_pendingRequests.Remove(requestId);
}
}
// 插件注册通信端点
public void RegisterPluginEndpoints(string pluginName, IPlugin plugin)
{
// 自动发现插件中的消息处理方法
var methods = plugin.GetType().GetMethods(BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic);
foreach (var method in methods)
{
var messageHandlerAttr = method.GetCustomAttribute<MessageHandlerAttribute>();
if (messageHandlerAttr != null)
{
var messageType = messageHandlerAttr.MessageType;
// 创建委托
var handlerType = typeof(MessageHandler<>)
.MakeGenericType(method.GetParameters()[0].ParameterType);
var handler = Delegate.CreateDelegate(handlerType, plugin, method);
Subscribe(messageType, handler);
}
}
}
}
// 消息处理特性
[AttributeUsage(AttributeTargets.Method)]
public class MessageHandlerAttribute : Attribute
{
public string MessageType { get; }
public MessageHandlerAttribute(string messageType)
{
MessageType = messageType;
}
}
// 使用示例
public class DataProcessorPlugin : IPlugin
{
[MessageHandler("DataProcessingRequest")]
public async Task HandleDataRequest(RequestMessage request)
{
if (request.Method == "ProcessData")
{
var data = request.Parameters[0] as string;
var processed = await ProcessDataAsync(data);
// 发送响应
var response = new ResponseMessage("DataProcessorPlugin",
request.RequestId, processed);
// 通过通信总线发送响应
// _communicationBus.PublishAsync(response);
}
}
private async Task<string> ProcessDataAsync(string data)
{
await Task.Delay(100); // 模拟处理时间
return $"Processed: {data}";
}
}
💻 实践篇:C# 下的插件式开发
1. 定义插件契约
csharp
// 核心插件契约
namespace PluginFramework
{
// 基础插件接口
public interface IPlugin : IDisposable
{
/// <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>
IPluginConfiguration Configuration { get; }
/// <summary>
/// 初始化插件
/// </summary>
/// <param name="context">插件上下文</param>
void Initialize(IPluginContext context);
/// <summary>
/// 启动插件
/// </summary>
void Start();
/// <summary>
/// 停止插件
/// </summary>
void Stop();
/// <summary>
/// 获取插件状态
/// </summary>
PluginStatus GetStatus();
}
// 插件状态枚举
public enum PluginStatus
{
NotLoaded,
Loaded,
Initialized,
Running,
Stopped,
Error,
Disposed
}
// 插件上下文接口
public interface IPluginContext
{
/// <summary>
/// 宿主程序信息
/// </summary>
IHostInfo HostInfo { get; }
/// <summary>
/// 日志记录器
/// </summary>
ILogger Logger { get; }
/// <summary>
/// 配置管理器
/// </summary>
IConfigurationManager ConfigurationManager { get; }
/// <summary>
/// 服务容器
/// </summary>
IServiceProvider ServiceProvider { get; }
/// <summary>
/// 事件总线
/// </summary>
IEventBus EventBus { get; }
/// <summary>
/// 获取其他插件
/// </summary>
IPlugin GetPlugin(string pluginId);
/// <summary>
/// 获取所有插件
/// </summary>
IEnumerable<IPlugin> GetAllPlugins();
}
// 配置相关接口
public interface IPluginConfiguration
{
T GetSetting<T>(string key, T defaultValue = default);
void SetSetting<T>(string key, T value);
bool HasSetting(string key);
void Save();
void Load();
}
// 支持异步操作的插件接口
public interface IAsyncPlugin : IPlugin
{
Task InitializeAsync(IPluginContext context, CancellationToken cancellationToken = default);
Task StartAsync(CancellationToken cancellationToken = default);
Task StopAsync(CancellationToken cancellationToken = default);
}
// 支持UI的插件接口
public interface IUIPlugin : IPlugin
{
/// <summary>
/// 插件UI元素
/// </summary>
UIElement GetUIElement();
/// <summary>
/// UI显示位置
/// </summary>
UILocation PreferredLocation { get; }
/// <summary>
/// UI大小
/// </summary>
Size PreferredSize { get; }
}
// UI位置枚举
public enum UILocation
{
MainWindow,
SidePanel,
Toolbar,
StatusBar,
Dialog,
ContextMenu
}
// 支持命令的插件接口
public interface ICommandPlugin : IPlugin
{
/// <summary>
/// 插件提供的命令
/// </summary>
IEnumerable<ICommand> Commands { get; }
/// <summary>
/// 执行命令
/// </summary>
Task<CommandResult> ExecuteCommand(string commandId,
Dictionary<string, object> parameters = null);
}
// 命令接口
public interface ICommand
{
string Id { get; }
string Name { get; }
string Description { get; }
string Icon { get; }
bool CanExecute(object parameter);
Task ExecuteAsync(object parameter);
}
// 命令结果
public class CommandResult
{
public bool Success { get; set; }
public string Message { get; set; }
public object Data { get; set; }
public Exception Error { get; set; }
public static CommandResult Ok(string message = null, object data = null)
=> new CommandResult { Success = true, Message = message, Data = data };
public static CommandResult Fail(string message, Exception error = null)
=> new CommandResult { Success = false, Message = message, Error = error };
}
}
// 插件元数据特性
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class PluginMetadataAttribute : Attribute
{
public string Id { get; }
public string Name { get; }
public string Version { get; }
public string Description { get; }
public string Author { get; }
public string[] Dependencies { get; set; }
public string[] Tags { get; set; }
public string Icon { get; set; }
public string Website { get; set; }
public string License { get; set; }
public PluginMetadataAttribute(string id, string name, string version,
string description = "", string author = "")
{
Id = id ?? throw new ArgumentNullException(nameof(id));
Name = name ?? throw new ArgumentNullException(nameof(name));
Version = version ?? throw new ArgumentNullException(nameof(version));
Description = description;
Author = author;
Dependencies = Array.Empty<string>();
Tags = Array.Empty<string>();
}
}
// 插件依赖特性
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class PluginDependencyAttribute : Attribute
{
public string PluginId { get; }
public string MinVersion { get; }
public string MaxVersion { get; }
public bool Optional { get; set; }
public PluginDependencyAttribute(string pluginId,
string minVersion = null,
string maxVersion = null)
{
PluginId = pluginId;
MinVersion = minVersion;
MaxVersion = maxVersion;
}
}
// 插件初始化特性
[AttributeUsage(AttributeTargets.Method)]
public class PluginInitializerAttribute : Attribute
{
public InitializationStage Stage { get; }
public int Order { get; set; }
public PluginInitializerAttribute(InitializationStage stage = InitializationStage.Normal)
{
Stage = stage;
}
}
public enum InitializationStage
{
Early, // 早期初始化
Normal, // 正常初始化
Late // 后期初始化
}
2. 实现一个具体插件
csharp
// 示例:图片处理插件
[PluginMetadata(
id: "com.example.imageprocessor",
name: "Image Processor Plugin",
version: "1.2.0",
description: "Provides image processing functionality",
author: "Example Corp",
Tags = new[] { "image", "processing", "filter" },
Icon = "icon.png",
Website = "https://example.com/plugins/image-processor",
License = "MIT"
)]
[PluginDependency("com.example.core", "1.0.0")]
[PluginDependency("com.example.ui", "2.0.0", Optional = true)]
public class ImageProcessorPlugin : IPlugin, ICommandPlugin, IUIPlugin
{
// 插件状态
private PluginStatus _status = PluginStatus.NotLoaded;
private IPluginContext _context;
private readonly List<ICommand> _commands = new List<ICommand>();
private ImageProcessor _processor;
private ImageProcessorUI _ui;
// IPlugin 实现
public string Id => "com.example.imageprocessor";
public string Name => "Image Processor Plugin";
public Version Version => new Version(1, 2, 0);
public string Description => "Provides image processing functionality";
public string Author => "Example Corp";
public IPluginConfiguration Configuration { get; private set; }
public void Initialize(IPluginContext context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
try
{
// 初始化配置
Configuration = new JsonPluginConfiguration("imageprocessor.config.json");
Configuration.Load();
// 初始化处理器
_processor = new ImageProcessor(Configuration);
// 注册命令
InitializeCommands();
// 初始化UI
_ui = new ImageProcessorUI(_processor);
// 订阅事件
context.EventBus.Subscribe<ImageLoadedEvent>(OnImageLoaded);
context.EventBus.Subscribe<ApplicationShutdownEvent>(OnShutdown);
_status = PluginStatus.Initialized;
_context.Logger.Info($"Plugin {Name} initialized successfully");
}
catch (Exception ex)
{
_status = PluginStatus.Error;
_context.Logger.Error($"Failed to initialize plugin {Name}: {ex}");
throw new PluginInitializationException($"Failed to initialize {Name}", ex);
}
}
private void InitializeCommands()
{
_commands.Add(new ApplyFilterCommand(_processor));
_commands.Add(new ResizeImageCommand(_processor));
_commands.Add(new ConvertFormatCommand(_processor));
_commands.Add(new BatchProcessCommand(_processor));
}
[PluginInitializer(InitializationStage.Late, Order = 100)]
private void InitializeUIComponents()
{
// 延迟初始化UI组件
if (_context.ServiceProvider.GetService(typeof(IUIService)) is IUIService uiService)
{
uiService.RegisterToolbarItem(new ToolbarItem
{
Id = "image-processor-tools",
Title = "Image Tools",
Icon = "image.png",
Command = new RelayCommand(() => ShowProcessorDialog())
});
}
}
public void Start()
{
if (_status != PluginStatus.Initialized && _status != PluginStatus.Stopped)
throw new InvalidOperationException($"Plugin is in {_status} state");
try
{
_processor.Start();
_status = PluginStatus.Running;
_context.Logger.Info($"Plugin {Name} started");
}
catch (Exception ex)
{
_status = PluginStatus.Error;
_context.Logger.Error($"Failed to start plugin {Name}: {ex}");
throw;
}
}
public void Stop()
{
if (_status != PluginStatus.Running)
return;
try
{
_processor.Stop();
_status = PluginStatus.Stopped;
_context.Logger.Info($"Plugin {Name} stopped");
}
catch (Exception ex)
{
_context.Logger.Error($"Error stopping plugin {Name}: {ex}");
}
}
public PluginStatus GetStatus() => _status;
// ICommandPlugin 实现
public IEnumerable<ICommand> Commands => _commands.AsReadOnly();
public async Task<CommandResult> ExecuteCommand(string commandId,
Dictionary<string, object> parameters = null)
{
var command = _commands.FirstOrDefault(c => c.Id == commandId);
if (command == null)
return CommandResult.Fail($"Command {commandId} not found");
try
{
await command.ExecuteAsync(parameters);
return CommandResult.Ok($"Command {commandId} executed successfully");
}
catch (Exception ex)
{
return CommandResult.Fail($"Command {commandId} failed: {ex.Message}", ex);
}
}
// IUIPlugin 实现
public UIElement GetUIElement() => _ui?.CreateUI();
public UILocation PreferredLocation => UILocation.SidePanel;
public Size PreferredSize => new Size(300, 500);
// 事件处理
private void OnImageLoaded(ImageLoadedEvent e)
{
if (_status == PluginStatus.Running)
{
// 自动处理新加载的图片
Task.Run(async () =>
{
try
{
var processed = await _processor.AutoProcessAsync(e.ImagePath);
_context.EventBus.Publish(new ImageProcessedEvent
{
OriginalPath = e.ImagePath,
ProcessedPath = processed,
Processor = Name
});
}
catch (Exception ex)
{
_context.Logger.Error($"Auto-processing failed for {e.ImagePath}: {ex}");
}
});
}
}
private void OnShutdown(ApplicationShutdownEvent e)
{
Stop();
}
// 清理资源
private bool _disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
Stop();
_processor?.Dispose();
_ui?.Dispose();
foreach (var command in _commands.OfType<IDisposable>())
{
command.Dispose();
}
_context?.EventBus.Unsubscribe<ImageLoadedEvent>(OnImageLoaded);
_context?.EventBus.Unsubscribe<ApplicationShutdownEvent>(OnShutdown);
}
_disposed = true;
_status = PluginStatus.Disposed;
}
}
~ImageProcessorPlugin()
{
Dispose(false);
}
// 内部命令类
private class ApplyFilterCommand : ICommand
{
private readonly ImageProcessor _processor;
public ApplyFilterCommand(ImageProcessor processor)
{
_processor = processor;
Id = "apply-filter";
Name = "Apply Filter";
Description = "Apply image filter";
Icon = "filter.png";
}
public string Id { get; }
public string Name { get; }
public string Description { get; }
public string Icon { get; }
public bool CanExecute(object parameter) => true;
public async Task ExecuteAsync(object parameter)
{
if (parameter is ImageProcessingParams args)
{
await _processor.ApplyFilterAsync(args);
}
}
}
// 更多命令类...
}
// 图像处理器实现
public class ImageProcessor : IDisposable
{
private readonly IPluginConfiguration _configuration;
private readonly ConcurrentQueue<ImageTask> _taskQueue;
private readonly CancellationTokenSource _cts;
private Task _processingTask;
public ImageProcessor(IPluginConfiguration configuration)
{
_configuration = configuration;
_taskQueue = new ConcurrentQueue<ImageTask>();
_cts = new CancellationTokenSource();
}
public void Start()
{
_processingTask = Task.Run(async () => await ProcessQueueAsync(_cts.Token));
}
public void Stop()
{
_cts.Cancel();
_processingTask?.Wait(TimeSpan.FromSeconds(5));
}
private async Task ProcessQueueAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
if (_taskQueue.TryDequeue(out var task))
{
try
{
await ProcessImageAsync(task);
}
catch (Exception ex)
{
task.CompletionSource.TrySetException(ex);
}
}
else
{
await Task.Delay(100, cancellationToken);
}
}
}
public async Task<string> AutoProcessAsync(string imagePath)
{
var filters = _configuration.GetSetting<string[]>("autoFilters",
new[] { "auto_contrast", "sharpen" });
var outputDir = _configuration.GetSetting("outputDirectory",
Path.Combine(Path.GetTempPath(), "processed_images"));
Directory.CreateDirectory(outputDir);
var outputPath = Path.Combine(outputDir,
$"{Path.GetFileNameWithoutExtension(imagePath)}_processed{Path.GetExtension(imagePath)}");
await ApplyFiltersAsync(imagePath, outputPath, filters);
return outputPath;
}
public async Task ApplyFilterAsync(ImageProcessingParams parameters)
{
using (var image = await LoadImageAsync(parameters.InputPath))
{
foreach (var filter in parameters.Filters)
{
image = await ApplyFilterInternalAsync(image, filter);
}
await SaveImageAsync(image, parameters.OutputPath);
}
}
private async Task<Image> LoadImageAsync(string path)
{
return await Task.Run(() =>
{
// 使用System.Drawing或ImageSharp等库
return Image.Load(path);
});
}
public void Dispose()
{
_cts?.Cancel();
_cts?.Dispose();
_processingTask?.Dispose();
}
}
// 配置类
public class JsonPluginConfiguration : IPluginConfiguration
{
private readonly string _configPath;
private Dictionary<string, object> _settings;
private readonly object _lock = new object();
public JsonPluginConfiguration(string configPath)
{
_configPath = configPath;
_settings = new Dictionary<string, object>();
}
public T GetSetting<T>(string key, T defaultValue = default)
{
lock (_lock)
{
if (_settings.TryGetValue(key, out var value))
{
try
{
return (T)Convert.ChangeType(value, typeof(T));
}
catch
{
return defaultValue;
}
}
return defaultValue;
}
}
public void SetSetting<T>(string key, T value)
{
lock (_lock)
{
_settings[key] = value;
}
}
public bool HasSetting(string key)
{
lock (_lock)
{
return _settings.ContainsKey(key);
}
}
public void Save()
{
lock (_lock)
{
var json = JsonConvert.SerializeObject(_settings, Formatting.Indented);
File.WriteAllText(_configPath, json);
}
}
public void Load()
{
lock (_lock)
{
if (File.Exists(_configPath))
{
var json = File.ReadAllText(_configPath);
_settings = JsonConvert.DeserializeObject<Dictionary<string, object>>(json)
?? new Dictionary<string, object>();
}
}
}
}
3. 构建宿主程序(插件加载器)
csharp
// 完整的插件宿主程序
namespace PluginHost
{
public class PluginHostApplication : IDisposable
{
private readonly string _pluginsDirectory;
private readonly ILogger _logger;
private readonly IConfiguration _configuration;
private readonly PluginManager _pluginManager;
private readonly PluginLoader _pluginLoader;
private readonly DependencyResolver _dependencyResolver;
private readonly ServiceProvider _serviceProvider;
private readonly EventAggregator _eventAggregator;
private readonly UIManager _uiManager;
private readonly CommandManager _commandManager;
// 插件目录结构
// plugins/
// ├── installed/ # 已安装插件
// ├── cache/ # 插件缓存
// ├── temp/ # 临时目录
// └── config/ # 插件配置
public PluginHostApplication(string baseDirectory)
{
_pluginsDirectory = Path.Combine(baseDirectory, "plugins");
// 初始化基础服务
_logger = CreateLogger();
_configuration = LoadConfiguration();
_serviceProvider = ConfigureServices();
// 初始化插件系统组件
_pluginLoader = new PluginLoader(_pluginsDirectory, _logger);
_dependencyResolver = new DependencyResolver(_logger);
_eventAggregator = new EventAggregator(_logger);
_uiManager = new UIManager(_serviceProvider);
_commandManager = new CommandManager();
// 初始化插件管理器
_pluginManager = new PluginManager(
_pluginLoader,
_dependencyResolver,
_eventAggregator,
_uiManager,
_commandManager,
_logger,
_configuration);
EnsureDirectories();
}
private void EnsureDirectories()
{
var directories = new[]
{
_pluginsDirectory,
Path.Combine(_pluginsDirectory, "installed"),
Path.Combine(_pluginsDirectory, "cache"),
Path.Combine(_pluginsDirectory, "temp"),
Path.Combine(_pluginsDirectory, "config")
};
foreach (var dir in directories)
{
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
}
}
private ServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
// 注册核心服务
services.AddSingleton<ILogger>(_logger);
services.AddSingleton<IConfiguration>(_configuration);
services.AddSingleton<IEventAggregator>(_eventAggregator);
services.AddSingleton<IUIManager>(_uiManager);
services.AddSingleton<ICommandManager>(_commandManager);
// 注册文件服务
services.AddSingleton<IFileSystem, PhysicalFileSystem>();
// 注册插件相关服务
services.AddSingleton<IPluginManager>(_pluginManager);
services.AddSingleton<IPluginLoader>(_pluginLoader);
services.AddSingleton<IPluginInstaller, PluginInstaller>();
services.AddSingleton<IPluginUpdater, PluginUpdater>();
return services.BuildServiceProvider();
}
public async Task InitializeAsync()
{
_logger.Info("Initializing plugin host application...");
try
{
// 发现插件
await _pluginLoader.DiscoverPluginsAsync();
// 解析依赖
var dependencyGraph = _dependencyResolver.BuildGraph(
_pluginLoader.GetDiscoveredPlugins());
// 验证插件
var validationResults = await ValidatePluginsAsync(
_pluginLoader.GetDiscoveredPlugins());
// 初始化插件管理器
await _pluginManager.InitializeAsync(dependencyGraph);
// 加载核心插件
await LoadCorePluginsAsync();
// 初始化UI
await _uiManager.InitializeAsync();
_logger.Info("Plugin host application initialized successfully");
}
catch (Exception ex)
{
_logger.Error($"Failed to initialize plugin host: {ex}");
throw;
}
}
private async Task LoadCorePluginsAsync()
{
var corePlugins = _pluginLoader.GetDiscoveredPlugins()
.Where(p => p.Tags?.Contains("core") == true)
.OrderBy(p => p.LoadOrder);
foreach (var pluginInfo in corePlugins)
{
try
{
await _pluginManager.LoadPluginAsync(pluginInfo.Id);
_logger.Info($"Loaded core plugin: {pluginInfo.Name}");
}
catch (Exception ex)
{
_logger.Error($"Failed to load core plugin {pluginInfo.Name}: {ex}");
}
}
}
public async Task StartAsync()
{
_logger.Info("Starting plugin host application...");
try
{
// 启动所有已加载插件
await _pluginManager.StartAllPluginsAsync();
// 发布应用程序启动事件
await _eventAggregator.PublishAsync(new ApplicationStartedEvent());
_logger.Info("Plugin host application started successfully");
}
catch (Exception ex)
{
_logger.Error($"Failed to start plugin host: {ex}");
throw;
}
}
public async Task StopAsync()
{
_logger.Info("Stopping plugin host application...");
try
{
// 发布应用程序停止事件
await _eventAggregator.PublishAsync(new ApplicationStoppingEvent());
// 停止所有插件(按依赖逆序)
await _pluginManager.StopAllPluginsAsync();
_logger.Info("Plugin host application stopped successfully");
}
catch (Exception ex)
{
_logger.Error($"Error stopping plugin host: {ex}");
}
}
public async Task InstallPluginAsync(string pluginPackagePath)
{
var installer = _serviceProvider.GetRequiredService<IPluginInstaller>();
await installer.InstallAsync(pluginPackagePath);
}
public async Task UninstallPluginAsync(string pluginId)
{
var installer = _serviceProvider.GetRequiredService<IPluginInstaller>();
await installer.UninstallAsync(pluginId);
}
public async Task UpdatePluginAsync(string pluginId)
{
var updater = _serviceProvider.GetRequiredService<IPluginUpdater>();
await updater.UpdateAsync(pluginId);
}
public IReadOnlyDictionary<string, PluginInfo> GetInstalledPlugins()
=> _pluginManager.GetInstalledPlugins();
public IReadOnlyDictionary<string, PluginInfo> GetLoadedPlugins()
=> _pluginManager.GetLoadedPlugins();
public PluginStatus GetPluginStatus(string pluginId)
=> _pluginManager.GetPluginStatus(pluginId);
public void Dispose()
{
StopAsync().Wait(TimeSpan.FromSeconds(10));
_pluginManager?.Dispose();
_serviceProvider?.Dispose();
_logger?.Dispose();
GC.SuppressFinalize(this);
}
}
// 插件管理器实现
public class PluginManager : IPluginManager, IDisposable
{
private readonly IPluginLoader _loader;
private readonly DependencyResolver _dependencyResolver;
private readonly IEventAggregator _eventAggregator;
private readonly IUIManager _uiManager;
private readonly ICommandManager _commandManager;
private readonly ILogger _logger;
private readonly IConfiguration _configuration;
private readonly Dictionary<string, PluginContext> _plugins;
private readonly Dictionary<string, PluginInfo> _pluginInfos;
private readonly PluginScheduler _scheduler;
private readonly PluginMonitor _monitor;
private readonly object _lock = new object();
public PluginManager(
IPluginLoader loader,
DependencyResolver dependencyResolver,
IEventAggregator eventAggregator,
IUIManager uiManager,
ICommandManager commandManager,
ILogger logger,
IConfiguration configuration)
{
_loader = loader;
_dependencyResolver = dependencyResolver;
_eventAggregator = eventAggregator;
_uiManager = uiManager;
_commandManager = commandManager;
_logger = logger;
_configuration = configuration;
_plugins = new Dictionary<string, PluginContext>();
_pluginInfos = new Dictionary<string, PluginInfo>();
_scheduler = new PluginScheduler(logger);
_monitor = new PluginMonitor(logger);
}
public async Task InitializeAsync(DependencyGraph dependencyGraph)
{
_logger.Info("Initializing plugin manager...");
// 加载插件信息
var discoveredPlugins = _loader.GetDiscoveredPlugins();
foreach (var info in discoveredPlugins)
{
_pluginInfos[info.Id] = info;
}
// 初始化调度器
await _scheduler.InitializeAsync();
// 初始化监视器
await _monitor.InitializeAsync();
_logger.Info($"Plugin manager initialized with {discoveredPlugins.Count} plugins discovered");
}
public async Task LoadPluginAsync(string pluginId)
{
lock (_lock)
{
if (_plugins.ContainsKey(pluginId))
throw new PluginAlreadyLoadedException(pluginId);
}
if (!_pluginInfos.TryGetValue(pluginId, out var pluginInfo))
throw new PluginNotFoundException(pluginId);
_logger.Info($"Loading plugin: {pluginInfo.Name} v{pluginInfo.Version}");
try
{
// 检查依赖
await CheckDependenciesAsync(pluginId);
// 创建插件上下文
var context = new PluginContext
{
PluginInfo = pluginInfo,
Status = PluginStatus.Loading,
LoadTime = DateTime.UtcNow
};
lock (_lock)
{
_plugins[pluginId] = context;
}
// 加载插件程序集
var assembly = await _loader.LoadPluginAssemblyAsync(pluginInfo);
// 创建插件实例
var plugin = CreatePluginInstance(assembly, pluginInfo);
// 创建插件上下文
var pluginContext = new PluginHostContext(
pluginId,
_eventAggregator,
_uiManager,
_commandManager,
_logger,
_configuration);
// 初始化插件
await InitializePluginAsync(plugin, pluginContext);
context.Plugin = plugin;
context.PluginHostContext = pluginContext;
context.Status = PluginStatus.Loaded;
// 注册UI组件
RegisterPluginUI(plugin, pluginId);
// 注册命令
RegisterPluginCommands(plugin, pluginId);
// 开始监视
_monitor.StartMonitoring(pluginId, plugin);
_logger.Info($"Plugin {pluginInfo.Name} loaded successfully");
// 发布插件加载事件
await _eventAggregator.PublishAsync(new PluginLoadedEvent
{
PluginId = pluginId,
PluginName = pluginInfo.Name,
Version = pluginInfo.Version
});
}
catch (Exception ex)
{
lock (_lock)
{
_plugins.Remove(pluginId);
}
_logger.Error($"Failed to load plugin {pluginId}: {ex}");
throw new PluginLoadException($"Failed to load plugin {pluginId}", ex);
}
}
private async Task CheckDependenciesAsync(string pluginId)
{
var dependencies = _dependencyResolver.GetDependencies(pluginId);
foreach (var dep in dependencies)
{
if (!_plugins.ContainsKey(dep))
{
try
{
await LoadPluginAsync(dep);
}
catch (Exception ex)
{
throw new DependencyLoadException(
$"Failed to load dependency {dep} for plugin {pluginId}", ex);
}
}
}
}
private IPlugin CreatePluginInstance(Assembly assembly, PluginInfo pluginInfo)
{
var pluginType = assembly.GetTypes()
.FirstOrDefault(t => typeof(IPlugin).IsAssignableFrom(t) &&
!t.IsAbstract);
if (pluginType == null)
throw new InvalidPluginException($"No IPlugin implementation found in {assembly.FullName}");
try
{
return (IPlugin)Activator.CreateInstance(pluginType);
}
catch (Exception ex)
{
throw new PluginInstantiationException(
$"Failed to create instance of {pluginType.FullName}", ex);
}
}
private async Task InitializePluginAsync(IPlugin plugin, IPluginContext context)
{
if (plugin is IAsyncPlugin asyncPlugin)
{
await asyncPlugin.InitializeAsync(context);
}
else
{
plugin.Initialize(context);
}
}
private void RegisterPluginUI(IPlugin plugin, string pluginId)
{
if (plugin is IUIPlugin uiPlugin)
{
_uiManager.RegisterPluginUI(pluginId, uiPlugin);
}
}
private void RegisterPluginCommands(IPlugin plugin, string pluginId)
{
if (plugin is ICommandPlugin commandPlugin)
{
foreach (var command in commandPlugin.Commands)
{
_commandManager.RegisterCommand(pluginId, command);
}
}
}
public async Task StartPluginAsync(string pluginId)
{
if (!_plugins.TryGetValue(pluginId, out var context))
throw new PluginNotFoundException(pluginId);
if (context.Status != PluginStatus.Loaded &&
context.Status != PluginStatus.Stopped)
throw new InvalidPluginStateException(
$"Cannot start plugin in {context.Status} state");
_logger.Info($"Starting plugin: {context.PluginInfo.Name}");
try
{
context.Status = PluginStatus.Starting;
if (context.Plugin is IAsyncPlugin asyncPlugin)
{
await asyncPlugin.StartAsync();
}
else
{
context.Plugin.Start();
}
context.Status = PluginStatus.Running;
context.StartTime = DateTime.UtcNow;
_logger.Info($"Plugin {context.PluginInfo.Name} started successfully");
await _eventAggregator.PublishAsync(new PluginStartedEvent
{
PluginId = pluginId,
PluginName = context.PluginInfo.Name
});
}
catch (Exception ex)
{
context.Status = PluginStatus.Error;
context.LastError = ex;
_logger.Error($"Failed to start plugin {pluginId}: {ex}");
throw new PluginStartException($"Failed to start plugin {pluginId}", ex);
}
}
public async Task StopPluginAsync(string pluginId)
{
if (!_plugins.TryGetValue(pluginId, out var context))
return;
if (context.Status != PluginStatus.Running)
return;
_logger.Info($"Stopping plugin: {context.PluginInfo.Name}");
try
{
context.Status = PluginStatus.Stopping;
// 检查是否有依赖于此插件的插件
var dependents = _dependencyResolver.GetDependents(pluginId)
.Where(depId => _plugins.ContainsKey(depId) &&
_plugins[depId].Status == PluginStatus.Running)
.ToList();
if (dependents.Count > 0)
{
_logger.Warning($"Plugin {pluginId} has running dependents: " +
$"{string.Join(", ", dependents)}");
}
if (context.Plugin is IAsyncPlugin asyncPlugin)
{
await asyncPlugin.StopAsync();
}
else
{
context.Plugin.Stop();
}
context.Status = PluginStatus.Stopped;
context.StopTime = DateTime.UtcNow;
_monitor.StopMonitoring(pluginId);
_logger.Info($"Plugin {context.PluginInfo.Name} stopped successfully");
await _eventAggregator.PublishAsync(new PluginStoppedEvent
{
PluginId = pluginId,
PluginName = context.PluginInfo.Name
});
}
catch (Exception ex)
{
context.Status = PluginStatus.Error;
context.LastError = ex;
_logger.Error($"Error stopping plugin {pluginId}: {ex}");
}
}
public async Task UnloadPluginAsync(string pluginId)
{
if (!_plugins.TryGetValue(pluginId, out var context))
return;
// 先停止插件
if (context.Status == PluginStatus.Running)
{
await StopPluginAsync(pluginId);
}
_logger.Info($"Unloading plugin: {context.PluginInfo.Name}");
try
{
context.Status = PluginStatus.Unloading;
// 清理UI注册
_uiManager.UnregisterPluginUI(pluginId);
// 清理命令注册
_commandManager.UnregisterPluginCommands(pluginId);
// 释放插件资源
context.Plugin?.Dispose();
// 清理上下文
context.PluginHostContext?.Dispose();
lock (_lock)
{
_plugins.Remove(pluginId);
}
// 卸载程序集(如果支持)
if (_loader is IAssemblyUnloader unloader)
{
await unloader.UnloadAssemblyAsync(context.PluginInfo.AssemblyPath);
}
_logger.Info($"Plugin {context.PluginInfo.Name} unloaded successfully");
await _eventAggregator.PublishAsync(new PluginUnloadedEvent
{
PluginId = pluginId,
PluginName = context.PluginInfo.Name
});
}
catch (Exception ex)
{
_logger.Error($"Error unloading plugin {pluginId}: {ex}");
throw;
}
}
public async Task StartAllPluginsAsync()
{
var loadOrder = _dependencyResolver.GetLoadOrder();
foreach (var pluginId in loadOrder)
{
if (_plugins.TryGetValue(pluginId, out var context) &&
context.Status == PluginStatus.Loaded)
{
await StartPluginAsync(pluginId);
}
}
}
public async Task StopAllPluginsAsync()
{
var stopOrder = _dependencyResolver.GetStopOrder();
foreach (var pluginId in stopOrder)
{
await StopPluginAsync(pluginId);
}
}
public IReadOnlyDictionary<string, PluginInfo> GetInstalledPlugins()
{
return new ReadOnlyDictionary<string, PluginInfo>(_pluginInfos);
}
public IReadOnlyDictionary<string, PluginInfo> GetLoadedPlugins()
{
var loadedInfos = _plugins.ToDictionary(
kv => kv.Key,
kv => kv.Value.PluginInfo);
return new ReadOnlyDictionary<string, PluginInfo>(loadedInfos);
}
public PluginStatus GetPluginStatus(string pluginId)
{
return _plugins.TryGetValue(pluginId, out var context)
? context.Status
: PluginStatus.NotLoaded;
}
public PluginDiagnostics GetPluginDiagnostics(string pluginId)
{
if (!_plugins.TryGetValue(pluginId, out var context))
return null;
return new PluginDiagnostics
{
PluginId = pluginId,
Status = context.Status,
LoadTime = context.LoadTime,
StartTime = context.StartTime,
StopTime = context.StopTime,
LastError = context.LastError?.Message,
PerformanceMetrics = _monitor.GetMetrics(pluginId),
MemoryUsage = _monitor.GetMemoryUsage(pluginId)
};
}
public void Dispose()
{
StopAllPluginsAsync().Wait(TimeSpan.FromSeconds(30));
foreach (var context in _plugins.Values)
{
try
{
context.Plugin?.Dispose();
context.PluginHostContext?.Dispose();
}
catch (Exception ex)
{
_logger.Error($"Error disposing plugin {context.PluginInfo.Id}: {ex}");
}
}
_plugins.Clear();
_scheduler.Dispose();
_monitor.Dispose();
}
private class PluginContext
{
public PluginInfo PluginInfo { get; set; }
public IPlugin Plugin { get; set; }
public IPluginContext PluginHostContext { get; set; }
public PluginStatus Status { get; set; }
public DateTime LoadTime { get; set; }
public DateTime? StartTime { get; set; }
public DateTime? StopTime { get; set; }
public Exception LastError { get; set; }
}
}
}
应用案例:可扩展的日志系统
csharp
// 可扩展的日志系统插件架构
namespace ExtensibleLoggingSystem
{
// 日志级别
public enum LogLevel
{
Trace,
Debug,
Information,
Warning,
Error,
Critical
}
// 日志记录接口
public interface ILogRecord
{
DateTime Timestamp { get; }
LogLevel Level { get; }
string Message { get; }
string Category { get; }
Exception Exception { get; }
Dictionary<string, object> Properties { get; }
}
// 日志接收器接口
public interface ILogSink : IPlugin
{
string SinkType { get; }
bool IsEnabled { get; set; }
LogLevel MinimumLevel { get; set; }
Task WriteAsync(ILogRecord record);
Task FlushAsync();
}
// 日志格式化器接口
public interface ILogFormatter : IPlugin
{
string Format { get; }
string FormatRecord(ILogRecord record);
}
// 日志过滤器接口
public interface ILogFilter : IPlugin
{
bool ShouldLog(ILogRecord record);
}
// 日志上下文提供器接口
public interface ILogContextProvider : IPlugin
{
Dictionary<string, object> GetContextProperties();
}
// 可扩展的日志管理器
public class ExtensibleLogger : IDisposable
{
private readonly List<ILogSink> _sinks = new List<ILogSink>();
private readonly List<ILogFormatter> _formatters = new List<ILogFormatter>();
private readonly List<ILogFilter> _filters = new List<ILogFilter>();
private readonly List<ILogContextProvider> _contextProviders = new List<ILogContextProvider>();
private readonly ConcurrentQueue<LogRecord> _logQueue = new ConcurrentQueue<LogRecord>();
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private Task _processingTask;
public ExtensibleLogger(IPluginManager pluginManager)
{
// 从插件管理器获取所有日志相关插件
var plugins = pluginManager.GetLoadedPlugins();
foreach (var plugin in plugins.Values)
{
if (plugin.Instance is ILogSink sink)
{
_sinks.Add(sink);
}
else if (plugin.Instance is ILogFormatter formatter)
{
_formatters.Add(formatter);
}
else if (plugin.Instance is ILogFilter filter)
{
_filters.Add(filter);
}
else if (plugin.Instance is ILogContextProvider provider)
{
_contextProviders.Add(provider);
}
}
// 启动日志处理任务
_processingTask = Task.Run(ProcessLogQueueAsync);
}
public void Log(LogLevel level, string message, string category = null,
Exception exception = null,
Dictionary<string, object> properties = null)
{
var record = new LogRecord
{
Timestamp = DateTime.UtcNow,
Level = level,
Message = message,
Category = category,
Exception = exception,
Properties = MergeProperties(properties)
};
_logQueue.Enqueue(record);
}
private Dictionary<string, object> MergeProperties(Dictionary<string, object> properties)
{
var result = new Dictionary<string, object>();
// 添加上下文属性
foreach (var provider in _contextProviders)
{
var contextProps = provider.GetContextProperties();
if (contextProps != null)
{
foreach (var kvp in contextProps)
{
result[kvp.Key] = kvp.Value;
}
}
}
// 添加特定日志属性
if (properties != null)
{
foreach (var kvp in properties)
{
result[kvp.Key] = kvp.Value;
}
}
return result;
}
private async Task ProcessLogQueueAsync()
{
while (!_cts.IsCancellationRequested)
{
try
{
if (_logQueue.TryDequeue(out var record))
{
// 应用过滤器
if (!ShouldLog(record))
continue;
// 格式化记录(如果需要)
var formattedRecord = FormatRecord(record);
// 发送到所有启用的接收器
var tasks = new List<Task>();
foreach (var sink in _sinks.Where(s => s.IsEnabled &&
s.MinimumLevel <= record.Level))
{
tasks.Add(sink.WriteAsync(formattedRecord));
}
await Task.WhenAll(tasks);
}
else
{
await Task.Delay(10, _cts.Token);
}
}
catch (Exception ex)
{
// 日志系统本身的错误处理
Console.Error.WriteLine($"Log system error: {ex.Message}");
}
}
}
private bool ShouldLog(ILogRecord record)
{
foreach (var filter in _filters)
{
if (!filter.ShouldLog(record))
return false;
}
return true;
}
private ILogRecord FormatRecord(ILogRecord record)
{
// 如果有特定的格式化器,使用它们
foreach (var formatter in _formatters)
{
// 可以根据记录属性选择格式化器
if (record.Properties.TryGetValue("Format", out var format) &&
format?.ToString() == formatter.Format)
{
return new FormattedLogRecord(record, formatter.FormatRecord(record));
}
}
return record;
}
public async Task FlushAsync()
{
var tasks = _sinks.Select(s => s.FlushAsync()).ToList();
await Task.WhenAll(tasks);
}
public void Dispose()
{
_cts.Cancel();
_processingTask?.Wait(TimeSpan.FromSeconds(5));
_processingTask?.Dispose();
_cts.Dispose();
}
// 便利方法
public void LogInformation(string message, string category = null)
=> Log(LogLevel.Information, message, category);
public void LogWarning(string message, string category = null, Exception ex = null)
=> Log(LogLevel.Warning, message, category, ex);
public void LogError(string message, string category = null, Exception ex = null)
=> Log(LogLevel.Error, message, category, ex);
public void LogDebug(string message, string category = null)
=> Log(LogLevel.Debug, message, category);
}
// 具体插件实现示例
[PluginMetadata(
id: "com.example.logging.console",
name: "Console Log Sink",
version: "1.0.0",
description: "Outputs logs to console",
author: "Example Corp",
Tags = new[] { "logging", "console" }
)]
public class ConsoleLogSink : ILogSink
{
public string SinkType => "Console";
public bool IsEnabled { get; set; } = true;
public LogLevel MinimumLevel { get; set; } = LogLevel.Information;
private readonly object _lock = new object();
public Task WriteAsync(ILogRecord record)
{
return Task.Run(() =>
{
lock (_lock)
{
var color = GetColorForLevel(record.Level);
var originalColor = Console.ForegroundColor;
Console.ForegroundColor = color;
Console.WriteLine($"[{record.Timestamp:HH:mm:ss}] [{record.Level}] {record.Message}");
if (record.Exception != null)
{
Console.WriteLine($"Exception: {record.Exception}");
}
Console.ForegroundColor = originalColor;
}
});
}
private ConsoleColor GetColorForLevel(LogLevel level)
{
return level switch
{
LogLevel.Trace => ConsoleColor.Gray,
LogLevel.Debug => ConsoleColor.White,
LogLevel.Information => ConsoleColor.Green,
LogLevel.Warning => ConsoleColor.Yellow,
LogLevel.Error => ConsoleColor.Red,
LogLevel.Critical => ConsoleColor.DarkRed,
_ => ConsoleColor.White
};
}
public Task FlushAsync() => Task.CompletedTask;
// IPlugin 实现
public string Id => "com.example.logging.console";
public string Name => "Console Log Sink";
public Version Version => new Version(1, 0, 0);
public string Description => "Outputs logs to console";
public string Author => "Example Corp";
public IPluginConfiguration Configuration { get; private set; }
public void Initialize(IPluginContext context)
{
Configuration = context.ConfigurationManager.GetPluginConfiguration(Id);
Configuration.Load();
IsEnabled = Configuration.GetSetting("enabled", true);
MinimumLevel = Configuration.GetSetting("minLevel", LogLevel.Information);
}
public void Start() { }
public void Stop() { }
public PluginStatus GetStatus() => PluginStatus.Running;
public void Dispose() { }
}
[PluginMetadata(
id: "com.example.logging.file",
name: "File Log Sink",
version: "1.0.0",
description: "Writes logs to file",
author: "Example Corp",
Tags = new[] { "logging", "file" }
)]
public class FileLogSink : ILogSink
{
public string SinkType => "File";
public bool IsEnabled { get; set; } = true;
public LogLevel MinimumLevel { get; set; } = LogLevel.Information;
private StreamWriter _writer;
private readonly object _lock = new object();
private string _logDirectory;
private string _currentLogFile;
private Timer _rolloverTimer;
public async Task WriteAsync(ILogRecord record)
{
var logLine = $"[{record.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] " +
$"[{record.Level}] " +
$"[{record.Category}] " +
$"{record.Message}";
if (record.Exception != null)
{
logLine += $" | Exception: {record.Exception}";
}
lock (_lock)
{
if (_writer != null)
{
_writer.WriteLine(logLine);
}
}
await Task.CompletedTask;
}
public async Task FlushAsync()
{
lock (_lock)
{
_writer?.Flush();
}
await Task.CompletedTask;
}
// IPlugin 实现
public string Id => "com.example.logging.file";
public string Name => "File Log Sink";
public Version Version => new Version(1, 0, 0);
public string Description => "Writes logs to file";
public string Author => "Example Corp";
public IPluginConfiguration Configuration { get; private set; }
public void Initialize(IPluginContext context)
{
Configuration = context.ConfigurationManager.GetPluginConfiguration(Id);
Configuration.Load();
IsEnabled = Configuration.GetSetting("enabled", true);
MinimumLevel = Configuration.GetSetting("minLevel", LogLevel.Information);
_logDirectory = Configuration.GetSetting("logDirectory",
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs"));
Directory.CreateDirectory(_logDirectory);
InitializeLogFile();
ScheduleRollover();
}
private void InitializeLogFile()
{
var fileName = $"log_{DateTime.Now:yyyyMMdd_HHmmss}.txt";
_currentLogFile = Path.Combine(_logDirectory, fileName);
lock (_lock)
{
_writer?.Dispose();
_writer = new StreamWriter(_currentLogFile, append: true)
{
AutoFlush = true
};
}
}
private void ScheduleRollover()
{
var rolloverInterval = Configuration.GetSetting("rolloverInterval", "daily");
TimeSpan interval;
switch (rolloverInterval.ToLower())
{
case "hourly":
interval = TimeSpan.FromHours(1);
break;
case "daily":
interval = TimeSpan.FromDays(1);
break;
case "weekly":
interval = TimeSpan.FromDays(7);
break;
default:
interval = TimeSpan.FromDays(1);
break;
}
_rolloverTimer = new Timer(RolloverLogFile, null, interval, interval);
}
private void RolloverLogFile(object state)
{
InitializeLogFile();
}
public void Start() { }
public void Stop()
{
_rolloverTimer?.Dispose();
lock (_lock)
{
_writer?.Dispose();
_writer = null;
}
}
public PluginStatus GetStatus() => PluginStatus.Running;
public void Dispose()
{
Stop();
}
}
[PluginMetadata(
id: "com.example.logging.json",
name: "JSON Log Formatter",
version: "1.0.0",
description: "Formats logs as JSON",
author: "Example Corp",
Tags = new[] { "logging", "formatter", "json" }
)]
public class JsonLogFormatter : ILogFormatter
{
public string Format => "JSON";
public string FormatRecord(ILogRecord record)
{
var logObject = new
{
timestamp = record.Timestamp,
level = record.Level.ToString(),
category = record.Category,
message = record.Message,
exception = record.Exception?.ToString(),
properties = record.Properties
};
return JsonConvert.SerializeObject(logObject, Formatting.Indented);
}
// IPlugin 实现
public string Id => "com.example.logging.json";
public string Name => "JSON Log Formatter";
public Version Version => new Version(1, 0, 0);
public string Description => "Formats logs as JSON";
public string Author => "Example Corp";
public IPluginConfiguration Configuration { get; private set; }
public void Initialize(IPluginContext context)
{
Configuration = context.ConfigurationManager.GetPluginConfiguration(Id);
}
public void Start() { }
public void Stop() { }
public PluginStatus GetStatus() => PluginStatus.Running;
public void Dispose() { }
}
[PluginMetadata(
id: "com.example.logging.filter",
name: "Category Log Filter",
version: "1.0.0",
description: "Filters logs by category",
author: "Example Corp",
Tags = new[] { "logging", "filter" }
)]
public class CategoryLogFilter : ILogFilter
{
private HashSet<string> _excludedCategories = new HashSet<string>();
private HashSet<string> _includedCategories = new HashSet<string>();
public bool ShouldLog(ILogRecord record)
{
if (record.Category == null)
return true;
// 如果在排除列表中,则过滤掉
if (_excludedCategories.Contains(record.Category))
return false;
// 如果指定了包含列表,则只记录包含的类别
if (_includedCategories.Count > 0 &&
!_includedCategories.Contains(record.Category))
return false;
return true;
}
// IPlugin 实现
public string Id => "com.example.logging.filter";
public string Name => "Category Log Filter";
public Version Version => new Version(1, 0, 0);
public string Description => "Filters logs by category";
public string Author => "Example Corp";
public IPluginConfiguration Configuration { get; private set; }
public void Initialize(IPluginContext context)
{
Configuration = context.ConfigurationManager.GetPluginConfiguration(Id);
Configuration.Load();
var excluded = Configuration.GetSetting<string[]>("excludedCategories",
Array.Empty<string>());
var included = Configuration.GetSetting<string[]>("includedCategories",
Array.Empty<string>());
_excludedCategories = new HashSet<string>(excluded, StringComparer.OrdinalIgnoreCase);
_includedCategories = new HashSet<string>(included, StringComparer.OrdinalIgnoreCase);
}
public void Start() { }
public void Stop() { }
public PluginStatus GetStatus() => PluginStatus.Running;
public void Dispose() { }
}
}
⚙️ 实践篇:C++ 下的插件式开发
1. 定义插件契约
cpp
// plugin_framework.h - C++插件框架头文件
#pragma once
#include <memory>
#include <string>
#include <vector>
#include <functional>
#include <unordered_map>
#include <chrono>
#ifdef _WIN32
#ifdef PLUGIN_EXPORTS
#define PLUGIN_API __declspec(dllexport)
#else
#define PLUGIN_API __declspec(dllimport)
#endif
#else
#define PLUGIN_API __attribute__((visibility("default")))
#endif
namespace PluginFramework
{
// 插件版本
struct Version
{
int major;
int minor;
int patch;
std::string toString() const
{
return std::to_string(major) + "." +
std::to_string(minor) + "." +
std::to_string(patch);
}
bool operator<(const Version& other) const
{
if (major != other.major) return major < other.major;
if (minor != other.minor) return minor < other.minor;
return patch < other.patch;
}
bool operator>=(const Version& other) const
{
return !(*this < other);
}
};
// 插件状态
enum class PluginStatus
{
NotLoaded,
Loaded,
Initializing,
Initialized,
Starting,
Running,
Stopping,
Stopped,
Error,
Unloaded
};
// 插件信息
struct PluginInfo
{
std::string id;
std::string name;
Version version;
std::string description;
std::string author;
std::string website;
std::string license;
std::vector<std::string> dependencies;
std::vector<std::string> tags;
};
// 插件上下文
class IPluginContext
{
public:
virtual ~IPluginContext() = default;
virtual std::string getHostName() const = 0;
virtual Version getHostVersion() const = 0;
virtual void logInfo(const std::string& message) = 0;
virtual void logWarning(const std::string& message) = 0;
virtual void logError(const std::string& message) = 0;
virtual void* getService(const std::string& serviceName) = 0;
virtual bool hasService(const std::string& serviceName) const = 0;
virtual std::shared_ptr<void> getSharedService(const std::string& serviceName) = 0;
};
// 插件接口
class IPlugin
{
public:
virtual ~IPlugin() = default;
virtual PluginInfo getPluginInfo() const = 0;
virtual PluginStatus getStatus() const = 0;
virtual bool initialize(std::shared_ptr<IPluginContext> context) = 0;
virtual bool start() = 0;
virtual bool stop() = 0;
virtual bool shutdown() = 0;
virtual std::string getLastError() const = 0;
};
// 配置接口
class IConfiguration
{
public:
virtual ~IConfiguration() = default;
virtual bool load(const std::string& filePath) = 0;
virtual bool save(const std::string& filePath) = 0;
template<typename T>
T getValue(const std::string& key, const T& defaultValue = T()) const;
template<typename T>
void setValue(const std::string& key, const T& value);
virtual bool hasKey(const std::string& key) const = 0;
virtual std::vector<std::string> getKeys() const = 0;
};
// 事件系统
class IEvent
{
public:
virtual ~IEvent() = default;
virtual std::string getType() const = 0;
virtual std::chrono::system_clock::time_point getTimestamp() const = 0;
virtual const void* getSource() const = 0;
};
class IEventBus
{
public:
virtual ~IEventBus() = default;
using EventHandler = std::function<void(const std::shared_ptr<IEvent>&)>;
virtual void subscribe(const std::string& eventType, EventHandler handler) = 0;
virtual void unsubscribe(const std::string& eventType, EventHandler handler) = 0;
virtual void publish(const std::shared_ptr<IEvent>& event) = 0;
virtual size_t getSubscriberCount(const std::string& eventType) const = 0;
};
// 插件工厂函数类型
typedef IPlugin* (*CreatePluginFunc)();
typedef void (*DestroyPluginFunc)(IPlugin*);
// 插件导出宏
#define EXPORT_PLUGIN(PluginClass) \
extern "C" { \
PLUGIN_API PluginFramework::IPlugin* createPlugin() { \
return new PluginClass(); \
} \
PLUGIN_API void destroyPlugin(PluginFramework::IPlugin* plugin) { \
if (plugin) { \
plugin->shutdown(); \
delete plugin; \
} \
} \
PLUGIN_API const char* getPluginName() { \
return PluginClass::staticGetPluginInfo().name.c_str(); \
} \
PLUGIN_API const char* getPluginVersion() { \
return PluginClass::staticGetPluginInfo().version.toString().c_str(); \
} \
}
}
2. 实现一个具体插件
cpp
// image_processor_plugin.h
#pragma once
#include "plugin_framework.h"
#include <opencv2/opencv.hpp>
#include <vector>
#include <memory>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <thread>
namespace ImageProcessing
{
// 图像处理参数
struct ImageProcessParams
{
std::string inputPath;
std::string outputPath;
std::vector<std::string> filters;
int quality = 95;
bool overwrite = false;
};
// 处理结果
struct ProcessResult
{
bool success;
std::string message;
std::string outputPath;
double processingTime; // 秒
};
// 图像处理器接口
class IImageProcessor
{
public:
virtual ~IImageProcessor() = default;
virtual ProcessResult processImage(const ImageProcessParams& params) = 0;
virtual std::vector<std::string> getAvailableFilters() const = 0;
virtual bool hasFilter(const std::string& filterName) const = 0;
};
// 图像处理器插件
class ImageProcessorPlugin : public PluginFramework::IPlugin,
public IImageProcessor
{
public:
static PluginFramework::PluginInfo staticGetPluginInfo()
{
PluginFramework::PluginInfo info;
info.id = "com.example.imageprocessor";
info.name = "Image Processor Plugin";
info.version = {1, 0, 0};
info.description = "Advanced image processing capabilities";
info.author = "Example Corp";
info.website = "https://example.com";
info.license = "MIT";
info.dependencies = {"com.example.core"};
info.tags = {"image", "processing", "opencv"};
return info;
}
// IPlugin 实现
PluginFramework::PluginInfo getPluginInfo() const override
{
return staticGetPluginInfo();
}
PluginFramework::PluginStatus getStatus() const override
{
std::lock_guard<std::mutex> lock(mutex_);
return status_;
}
bool initialize(std::shared_ptr<PluginFramework::IPluginContext> context) override
{
std::lock_guard<std::mutex> lock(mutex_);
if (status_ != PluginFramework::PluginStatus::NotLoaded)
{
lastError_ = "Plugin already initialized";
return false;
}
try
{
context_ = context;
status_ = PluginFramework::PluginStatus::Initializing;
// 初始化配置
config_ = loadConfiguration();
// 初始化OpenCV
if (!initializeOpenCV())
{
status_ = PluginFramework::PluginStatus::Error;
lastError_ = "Failed to initialize OpenCV";
return false;
}
// 注册事件处理器
if (auto eventBus = getEventBus())
{
eventBus->subscribe("ImageLoadEvent",
[this](const std::shared_ptr<PluginFramework::IEvent>& event) {
onImageLoaded(event);
});
}
// 启动处理线程
processingThread_ = std::thread(&ImageProcessorPlugin::processQueue, this);
status_ = PluginFramework::PluginStatus::Initialized;
context_->logInfo("ImageProcessorPlugin initialized successfully");
return true;
}
catch (const std::exception& e)
{
status_ = PluginFramework::PluginStatus::Error;
lastError_ = std::string("Initialization failed: ") + e.what();
context_->logError(lastError_);
return false;
}
}
bool start() override
{
std::lock_guard<std::mutex> lock(mutex_);
if (status_ != PluginFramework::PluginStatus::Initialized &&
status_ != PluginFramework::PluginStatus::Stopped)
{
lastError_ = "Plugin not in correct state for starting";
return false;
}
status_ = PluginFramework::PluginStatus::Running;
context_->logInfo("ImageProcessorPlugin started");
return true;
}
bool stop() override
{
std::lock_guard<std::mutex> lock(mutex_);
if (status_ != PluginFramework::PluginStatus::Running)
return true;
status_ = PluginFramework::PluginStatus::Stopping;
// 通知处理线程停止
{
std::lock_guard<std::mutex> queueLock(queueMutex_);
stopProcessing_ = true;
queueCondition_.notify_all();
}
// 等待处理线程结束
if (processingThread_.joinable())
{
processingThread_.join();
}
status_ = PluginFramework::PluginStatus::Stopped;
context_->logInfo("ImageProcessorPlugin stopped");
return true;
}
bool shutdown() override
{
stop();
std::lock_guard<std::mutex> lock(mutex_);
status_ = PluginFramework::PluginStatus::Unloaded;
// 清理资源
if (auto eventBus = getEventBus())
{
// 需要保存事件处理器引用以便取消订阅
}
context_.reset();
config_.reset();
return true;
}
std::string getLastError() const override
{
std::lock_guard<std::mutex> lock(mutex_);
return lastError_;
}
// IImageProcessor 实现
ProcessResult processImage(const ImageProcessParams& params) override
{
if (getStatus() != PluginFramework::PluginStatus::Running)
{
return {false, "Plugin not running", "", 0.0};
}
auto startTime = std::chrono::high_resolution_clock::now();
try
{
// 读取图像
cv::Mat image = cv::imread(params.inputPath, cv::IMREAD_COLOR);
if (image.empty())
{
return {false, "Failed to load image: " + params.inputPath, "", 0.0};
}
// 应用滤镜
cv::Mat processed = image.clone();
for (const auto& filter : params.filters)
{
processed = applyFilter(processed, filter);
}
// 保存图像
std::vector<int> compressionParams;
compressionParams.push_back(cv::IMWRITE_JPEG_QUALITY);
compressionParams.push_back(params.quality);
if (!cv::imwrite(params.outputPath, processed, compressionParams))
{
return {false, "Failed to save image: " + params.outputPath, "", 0.0};
}
auto endTime = std::chrono::high_resolution_clock::now();
double processingTime = std::chrono::duration<double>(endTime - startTime).count();
return {true, "Image processed successfully", params.outputPath, processingTime};
}
catch (const cv::Exception& e)
{
return {false, std::string("OpenCV error: ") + e.what(), "", 0.0};
}
catch (const std::exception& e)
{
return {false, std::string("Error: ") + e.what(), "", 0.0};
}
}
std::vector<std::string> getAvailableFilters() const override
{
return {
"grayscale",
"blur",
"sharpen",
"edge_detect",
"emboss",
"sepia",
"invert",
"brightness",
"contrast"
};
}
bool hasFilter(const std::string& filterName) const override
{
auto filters = getAvailableFilters();
return std::find(filters.begin(), filters.end(), filterName) != filters.end();
}
// 异步处理接口
using ProcessCallback = std::function<void(const ProcessResult&)>;
void processImageAsync(const ImageProcessParams& params, ProcessCallback callback)
{
std::lock_guard<std::mutex> lock(queueMutex_);
processQueue_.push({params, callback});
queueCondition_.notify_one();
}
private:
struct ProcessTask
{
ImageProcessParams params;
ProcessCallback callback;
};
mutable std::mutex mutex_;
PluginFramework::PluginStatus status_ = PluginFramework::PluginStatus::NotLoaded;
std::string lastError_;
std::shared_ptr<PluginFramework::IPluginContext> context_;
std::shared_ptr<PluginFramework::IConfiguration> config_;
std::thread processingThread_;
std::queue<ProcessTask> processQueue_;
std::mutex queueMutex_;
std::condition_variable queueCondition_;
bool stopProcessing_ = false;
std::shared_ptr<PluginFramework::IConfiguration> loadConfiguration()
{
// 从上下文获取配置管理器
if (auto configManager = static_cast<PluginFramework::IConfigurationManager*>(
context_->getService("ConfigurationManager")))
{
return configManager->getPluginConfiguration(getPluginInfo().id);
}
return nullptr;
}
std::shared_ptr<PluginFramework::IEventBus> getEventBus()
{
if (context_)
{
return std::static_pointer_cast<PluginFramework::IEventBus>(
context_->getSharedService("EventBus"));
}
return nullptr;
}
bool initializeOpenCV()
{
// 检查OpenCV版本
if (CV_VERSION_MAJOR < 4)
{
context_->logWarning("OpenCV version < 4.0 may have limited features");
}
// 初始化OpenCV的并行处理
cv::setNumThreads(std::thread::hardware_concurrency());
context_->logInfo("OpenCV initialized: " + std::string(cv::getVersionString()));
return true;
}
cv::Mat applyFilter(const cv::Mat& input, const std::string& filterName)
{
cv::Mat output;
if (filterName == "grayscale")
{
cv::cvtColor(input, output, cv::COLOR_BGR2GRAY);
cv::cvtColor(output, output, cv::COLOR_GRAY2BGR);
}
else if (filterName == "blur")
{
cv::GaussianBlur(input, output, cv::Size(5, 5), 0);
}
else if (filterName == "sharpen")
{
cv::Mat kernel = (cv::Mat_<float>(3, 3) <<
0, -1, 0,
-1, 5, -1,
0, -1, 0);
cv::filter2D(input, output, -1, kernel);
}
else if (filterName == "edge_detect")
{
cv::Mat gray, edges;
cv::cvtColor(input, gray, cv::COLOR_BGR2GRAY);
cv::Canny(gray, edges, 100, 200);
cv::cvtColor(edges, output, cv::COLOR_GRAY2BGR);
}
else if (filterName == "emboss")
{
cv::Mat kernel = (cv::Mat_<float>(3, 3) <<
-2, -1, 0,
-1, 1, 1,
0, 1, 2);
cv::filter2D(input, output, -1, kernel);
cv::add(output, cv::Scalar(128, 128, 128), output);
}
else if (filterName == "sepia")
{
cv::Mat kernel = (cv::Mat_<float>(3, 3) <<
0.272, 0.534, 0.131,
0.349, 0.686, 0.168,
0.393, 0.769, 0.189);
cv::transform(input, output, kernel);
}
else if (filterName == "invert")
{
output = cv::Scalar(255, 255, 255) - input;
}
else if (filterName == "brightness")
{
double brightness = 1.2; // 从配置获取
input.convertTo(output, -1, brightness, 0);
}
else if (filterName == "contrast")
{
double contrast = 1.5; // 从配置获取
input.convertTo(output, -1, contrast, 0);
}
else
{
// 未知滤镜,返回原图
output = input.clone();
}
return output;
}
void processQueue()
{
while (true)
{
ProcessTask task;
{
std::unique_lock<std::mutex> lock(queueMutex_);
queueCondition_.wait(lock, [this]() {
return !processQueue_.empty() || stopProcessing_;
});
if (stopProcessing_ && processQueue_.empty())
{
break;
}
if (!processQueue_.empty())
{
task = std::move(processQueue_.front());
processQueue_.pop();
}
}
if (task.callback)
{
ProcessResult result = processImage(task.params);
task.callback(result);
}
}
}
void onImageLoaded(const std::shared_ptr<PluginFramework::IEvent>& event)
{
// 自动处理加载的图像
if (auto imageEvent = std::dynamic_pointer_cast<ImageLoadEvent>(event))
{
ImageProcessParams params;
params.inputPath = imageEvent->getImagePath();
params.outputPath = generateOutputPath(params.inputPath);
params.filters = {"auto_contrast", "sharpen"};
processImageAsync(params, [this](const ProcessResult& result) {
if (result.success)
{
context_->logInfo("Auto-processed image: " + result.outputPath);
// 发布处理完成事件
if (auto eventBus = getEventBus())
{
auto processedEvent = std::make_shared<ImageProcessedEvent>(
result.outputPath, getPluginInfo().name);
eventBus->publish(processedEvent);
}
}
});
}
}
std::string generateOutputPath(const std::string& inputPath)
{
std::string outputDir = config_ ?
config_->getValue<std::string>("outputDirectory", "/tmp/processed") :
"/tmp/processed";
// 确保目录存在
std::filesystem::create_directories(outputDir);
std::string filename = std::filesystem::path(inputPath).filename().string();
std::string stem = std::filesystem::path(filename).stem().string();
std::string extension = std::filesystem::path(filename).extension().string();
return outputDir + "/" + stem + "_processed" + extension;
}
};
}
// 导出插件
EXPORT_PLUGIN(ImageProcessing::ImageProcessorPlugin)
3. 构建宿主程序(插件加载器)
cpp
// plugin_host.cpp - C++插件宿主程序
#include "plugin_framework.h"
#include <iostream>
#include <filesystem>
#include <vector>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <algorithm>
#include <dlfcn.h> // Linux/macOS
// Windows: #include <windows.h>
#ifdef _WIN32
#include <windows.h>
typedef HMODULE LibraryHandle;
#define LIBRARY_EXT ".dll"
#define LoadLibraryFunc LoadLibraryW
#define GetProcAddressFunc GetProcAddress
#define FreeLibraryFunc FreeLibrary
#else
typedef void* LibraryHandle;
#define LIBRARY_EXT ".so"
#define LoadLibraryFunc dlopen
#define GetProcAddressFunc dlsym
#define FreeLibraryFunc dlclose
#endif
namespace PluginHost
{
// 插件库包装器
class PluginLibrary
{
public:
PluginLibrary(const std::string& path)
: libraryPath_(path), handle_(nullptr)
{
}
~PluginLibrary()
{
unload();
}
bool load()
{
if (handle_) return true;
#ifdef _WIN32
std::wstring widePath = std::filesystem::path(libraryPath_).wstring();
handle_ = LoadLibraryW(widePath.c_str());
#else
handle_ = dlopen(libraryPath_.c_str(), RTLD_LAZY | RTLD_LOCAL);
#endif
if (!handle_)
{
lastError_ = getLastError();
return false;
}
// 获取插件工厂函数
createFunc_ = reinterpret_cast<PluginFramework::CreatePluginFunc>(
getSymbol("createPlugin"));
destroyFunc_ = reinterpret_cast<PluginFramework::DestroyPluginFunc>(
getSymbol("destroyPlugin"));
getNameFunc_ = reinterpret_cast<const char*(*)()>(
getSymbol("getPluginName"));
getVersionFunc_ = reinterpret_cast<const char*(*)()>(
getSymbol("getPluginVersion"));
if (!createFunc_ || !destroyFunc_ || !getNameFunc_ || !getVersionFunc_)
{
lastError_ = "Missing required plugin export functions";
unload();
return false;
}
return true;
}
void unload()
{
if (handle_)
{
FreeLibraryFunc(handle_);
handle_ = nullptr;
createFunc_ = nullptr;
destroyFunc_ = nullptr;
getNameFunc_ = nullptr;
getVersionFunc_ = nullptr;
}
}
PluginFramework::IPlugin* createPlugin() const
{
return createFunc_ ? createFunc_() : nullptr;
}
void destroyPlugin(PluginFramework::IPlugin* plugin) const
{
if (destroyFunc_ && plugin)
{
destroyFunc_(plugin);
}
}
std::string getPluginName() const
{
return getNameFunc_ ? getNameFunc_() : "";
}
std::string getPluginVersion() const
{
return getVersionFunc_ ? getVersionFunc_() : "";
}
bool isLoaded() const { return handle_ != nullptr; }
std::string getPath() const { return libraryPath_; }
std::string getLastError() const { return lastError_; }
private:
void* getSymbol(const char* name)
{
#ifdef _WIN32
return GetProcAddress(static_cast<HMODULE>(handle_), name);
#else
return dlsym(handle_, name);
#endif
}
std::string getLastError()
{
#ifdef _WIN32
DWORD error = GetLastError();
if (error == 0) return "";
LPSTR buffer = nullptr;
size_t size = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&buffer, 0, NULL);
std::string message(buffer, size);
LocalFree(buffer);
return message;
#else
const char* error = dlerror();
return error ? error : "";
#endif
}
std::string libraryPath_;
LibraryHandle handle_;
PluginFramework::CreatePluginFunc createFunc_ = nullptr;
PluginFramework::DestroyPluginFunc destroyFunc_ = nullptr;
const char*(*getNameFunc_)() = nullptr;
const char*(*getVersionFunc_)() = nullptr;
std::string lastError_;
};
// 插件管理器
class PluginManager
{
public:
struct PluginEntry
{
std::shared_ptr<PluginLibrary> library;
std::shared_ptr<PluginFramework::IPlugin> plugin;
PluginFramework::PluginInfo info;
PluginFramework::PluginStatus status;
std::chrono::system_clock::time_point loadTime;
std::string lastError;
};
PluginManager(std::shared_ptr<PluginFramework::IPluginContext> hostContext)
: hostContext_(hostContext)
{
}
bool loadPlugin(const std::string& pluginPath)
{
std::lock_guard<std::mutex> lock(mutex_);
// 检查是否已经加载
for (const auto& entry : plugins_)
{
if (entry.second.library->getPath() == pluginPath)
{
return true; // 已经加载
}
}
auto library = std::make_shared<PluginLibrary>(pluginPath);
if (!library->load())
{
std::cerr << "Failed to load plugin library: "
<< library->getLastError() << std::endl;
return false;
}
// 创建插件实例
auto plugin = std::shared_ptr<PluginFramework::IPlugin>(
library->createPlugin(),
[library](PluginFramework::IPlugin* p) {
if (p) library->destroyPlugin(p);
});
if (!plugin)
{
std::cerr << "Failed to create plugin instance" << std::endl;
return false;
}
// 获取插件信息
auto info = plugin->getPluginInfo();
std::string libraryName = library->getPluginName();
std::string libraryVersion = library->getPluginVersion();
// 验证信息一致性
if (info.name != libraryName ||
info.version.toString() != libraryVersion)
{
std::cerr << "Plugin info mismatch between metadata and library exports"
<< std::endl;
return false;
}
// 检查依赖
if (!checkDependencies(info))
{
std::cerr << "Missing dependencies for plugin: " << info.name << std::endl;
return false;
}
// 初始化插件
if (!plugin->initialize(hostContext_))
{
std::cerr << "Failed to initialize plugin: " << info.name
<< ", error: " << plugin->getLastError() << std::endl;
return false;
}
// 添加到管理器
PluginEntry entry;
entry.library = library;
entry.plugin = plugin;
entry.info = info;
entry.status = PluginFramework::PluginStatus::Loaded;
entry.loadTime = std::chrono::system_clock::now();
plugins_[info.id] = entry;
// 添加到依赖图
dependencyGraph_[info.id] = info.dependencies;
for (const auto& dep : info.dependencies)
{
reverseDependencyGraph_[dep].push_back(info.id);
}
std::cout << "Plugin loaded: " << info.name
<< " v" << info.version.toString() << std::endl;
return true;
}
bool unloadPlugin(const std::string& pluginId)
{
std::lock_guard<std::mutex> lock(mutex_);
auto it = plugins_.find(pluginId);
if (it == plugins_.end())
{
return false;
}
// 检查是否有其他插件依赖于此插件
auto reverseDeps = reverseDependencyGraph_.find(pluginId);
if (reverseDeps != reverseDependencyGraph_.end() &&
!reverseDeps->second.empty())
{
std::cerr << "Cannot unload plugin " << pluginId
<< ", it is depended on by: ";
for (const auto& dep : reverseDeps->second)
{
if (plugins_.find(dep) != plugins_.end())
{
std::cerr << dep << " ";
}
}
std::cerr << std::endl;
return false;
}
// 停止插件
if (it->second.status == PluginFramework::PluginStatus::Running)
{
it->second.plugin->stop();
}
// 关闭插件
it->second.plugin->shutdown();
// 从依赖图中移除
dependencyGraph_.erase(pluginId);
reverseDependencyGraph_.erase(pluginId);
// 从其他插件的依赖中移除
for (auto& pair : dependencyGraph_)
{
auto& deps = pair.second;
deps.erase(std::remove(deps.begin(), deps.end(), pluginId), deps.end());
}
plugins_.erase(it);
std::cout << "Plugin unloaded: " << pluginId << std::endl;
return true;
}
bool startPlugin(const std::string& pluginId)
{
std::lock_guard<std::mutex> lock(mutex_);
auto it = plugins_.find(pluginId);
if (it == plugins_.end())
{
return false;
}
if (it->second.status != PluginFramework::PluginStatus::Loaded &&
it->second.status != PluginFramework::PluginStatus::Stopped)
{
return false;
}
if (!it->second.plugin->start())
{
it->second.lastError = it->second.plugin->getLastError();
return false;
}
it->second.status = PluginFramework::PluginStatus::Running;
return true;
}
bool stopPlugin(const std::string& pluginId)
{
std::lock_guard<std::mutex> lock(mutex_);
auto it = plugins_.find(pluginId);
if (it == plugins_.end())
{
return false;
}
if (it->second.status != PluginFramework::PluginStatus::Running)
{
return true;
}
if (!it->second.plugin->stop())
{
it->second.lastError = it->second.plugin->getLastError();
return false;
}
it->second.status = PluginFramework::PluginStatus::Stopped;
return true;
}
void discoverPlugins(const std::string& directory)
{
namespace fs = std::filesystem;
if (!fs::exists(directory) || !fs::is_directory(directory))
{
std::cerr << "Plugin directory does not exist: " << directory << std::endl;
return;
}
std::lock_guard<std::mutex> lock(mutex_);
for (const auto& entry : fs::directory_iterator(directory))
{
if (entry.is_regular_file() &&
entry.path().extension().string() == LIBRARY_EXT)
{
try
{
// 尝试加载插件库获取基本信息(不初始化)
auto library = std::make_shared<PluginLibrary>(entry.path().string());
if (library->load())
{
auto plugin = library->createPlugin();
if (plugin)
{
auto info = plugin->getPluginInfo();
library->destroyPlugin(plugin);
discoveredPlugins_[info.id] = {
library, nullptr, info,
PluginFramework::PluginStatus::NotLoaded,
std::chrono::system_clock::time_point(),
""
};
std::cout << "Discovered plugin: " << info.name
<< " (" << info.id << ")" << std::endl;
}
else
{
library->unload();
}
}
}
catch (const std::exception& e)
{
std::cerr << "Error discovering plugin "
<< entry.path().string() << ": " << e.what() << std::endl;
}
}
}
}
std::vector<std::string> getLoadOrder() const
{
std::vector<std::string> order;
std::unordered_set<std::string> visited;
std::unordered_set<std::string> temp;
for (const auto& pair : dependencyGraph_)
{
if (visited.find(pair.first) == visited.end())
{
if (!topologicalSort(pair.first, visited, temp, order))
{
throw std::runtime_error("Circular dependency detected");
}
}
}
std::reverse(order.begin(), order.end());
return order;
}
void loadAllDiscovered()
{
auto order = getLoadOrder();
for (const auto& pluginId : order)
{
auto it = discoveredPlugins_.find(pluginId);
if (it != discoveredPlugins_.end())
{
loadPlugin(it->second.library->getPath());
}
}
}
void startAll()
{
std::lock_guard<std::mutex> lock(mutex_);
for (auto& pair : plugins_)
{
if (pair.second.status == PluginFramework::PluginStatus::Loaded)
{
startPlugin(pair.first);
}
}
}
void stopAll()
{
std::lock_guard<std::mutex> lock(mutex_);
// 按依赖逆序停止
auto order = getLoadOrder();
std::reverse(order.begin(), order.end());
for (const auto& pluginId : order)
{
if (plugins_.find(pluginId) != plugins_.end())
{
stopPlugin(pluginId);
}
}
}
std::vector<PluginFramework::PluginInfo> getLoadedPlugins() const
{
std::lock_guard<std::mutex> lock(mutex_);
std::vector<PluginFramework::PluginInfo> result;
for (const auto& pair : plugins_)
{
result.push_back(pair.second.info);
}
return result;
}
std::shared_ptr<PluginFramework::IPlugin> getPlugin(const std::string& pluginId) const
{
std::lock_guard<std::mutex> lock(mutex_);
auto it = plugins_.find(pluginId);
return it != plugins_.end() ? it->second.plugin : nullptr;
}
private:
bool checkDependencies(const PluginFramework::PluginInfo& info)
{
for (const auto& dep : info.dependencies)
{
if (plugins_.find(dep) == plugins_.end() &&
discoveredPlugins_.find(dep) == discoveredPlugins_.end())
{
return false;
}
}
return true;
}
bool topologicalSort(
const std::string& pluginId,
std::unordered_set<std::string>& visited,
std::unordered_set<std::string>& temp,
std::vector<std::string>& order) const
{
if (temp.find(pluginId) != temp.end())
{
return false; // 循环依赖
}
if (visited.find(pluginId) != visited.end())
{
return true;
}
temp.insert(pluginId);
auto it = dependencyGraph_.find(pluginId);
if (it != dependencyGraph_.end())
{
for (const auto& dep : it->second)
{
if (!topologicalSort(dep, visited, temp, order))
{
return false;
}
}
}
temp.erase(pluginId);
visited.insert(pluginId);
order.push_back(pluginId);
return true;
}
mutable std::mutex mutex_;
std::shared_ptr<PluginFramework::IPluginContext> hostContext_;
std::unordered_map<std::string, PluginEntry> plugins_;
std::unordered_map<std::string, PluginEntry> discoveredPlugins_;
std::unordered_map<std::string, std::vector<std::string>> dependencyGraph_;
std::unordered_map<std::string, std::vector<std::string>> reverseDependencyGraph_;
};
// 宿主应用程序
class HostApplication
{
public:
HostApplication()
{
// 创建宿主上下文
hostContext_ = createHostContext();
// 创建插件管理器
pluginManager_ = std::make_shared<PluginManager>(hostContext_);
// 初始化事件总线等核心服务
initializeCoreServices();
}
void run(const std::string& pluginDirectory)
{
std::cout << "Starting plugin host application..." << std::endl;
// 发现插件
pluginManager_->discoverPlugins(pluginDirectory);
// 加载所有插件
pluginManager_->loadAllDiscovered();
// 启动所有插件
pluginManager_->startAll();
std::cout << "Plugin host is running. Press Enter to stop..." << std::endl;
std::cin.get();
// 停止所有插件
pluginManager_->stopAll();
std::cout << "Plugin host stopped." << std::endl;
}
std::shared_ptr<PluginFramework::IPlugin> getPlugin(const std::string& pluginId)
{
return pluginManager_->getPlugin(pluginId);
}
private:
class HostContext : public PluginFramework::IPluginContext
{
public:
std::string getHostName() const override
{
return "C++ Plugin Host";
}
PluginFramework::Version getHostVersion() const override
{
return {1, 0, 0};
}
void logInfo(const std::string& message) override
{
std::cout << "[INFO] " << message << std::endl;
}
void logWarning(const std::string& message) override
{
std::cout << "[WARN] " << message << std::endl;
}
void logError(const std::string& message) override
{
std::cerr << "[ERROR] " << message << std::endl;
}
void* getService(const std::string& serviceName) override
{
// 简单服务查找
if (serviceName == "EventBus")
{
return eventBus_.get();
}
else if (serviceName == "ConfigurationManager")
{
return configManager_.get();
}
return nullptr;
}
bool hasService(const std::string& serviceName) const override
{
return serviceName == "EventBus" || serviceName == "ConfigurationManager";
}
std::shared_ptr<void> getSharedService(const std::string& serviceName) override
{
if (serviceName == "EventBus")
{
return eventBus_;
}
else if (serviceName == "ConfigurationManager")
{
return configManager_;
}
return nullptr;
}
void setEventBus(std::shared_ptr<PluginFramework::IEventBus> eventBus)
{
eventBus_ = eventBus;
}
void setConfigManager(std::shared_ptr<PluginFramework::IConfigurationManager> configManager)
{
configManager_ = configManager;
}
private:
std::shared_ptr<PluginFramework::IEventBus> eventBus_;
std::shared_ptr<PluginFramework::IConfigurationManager> configManager_;
};
std::shared_ptr<HostContext> createHostContext()
{
return std::make_shared<HostContext>();
}
void initializeCoreServices()
{
// 初始化事件总线
auto eventBus = std::make_shared<SimpleEventBus>();
hostContext_->setEventBus(eventBus);
// 初始化配置管理器
auto configManager = std::make_shared<SimpleConfigurationManager>();
hostContext_->setConfigManager(configManager);
}
// 简单事件总线实现
class SimpleEventBus : public PluginFramework::IEventBus
{
public:
void subscribe(const std::string& eventType, EventHandler handler) override
{
std::lock_guard<std::mutex> lock(mutex_);
subscribers_[eventType].push_back(handler);
}
void unsubscribe(const std::string& eventType, EventHandler handler) override
{
std::lock_guard<std::mutex> lock(mutex_);
auto it = subscribers_.find(eventType);
if (it != subscribers_.end())
{
auto& handlers = it->second;
handlers.erase(
std::remove(handlers.begin(), handlers.end(), handler),
handlers.end());
}
}
void publish(const std::shared_ptr<PluginFramework::IEvent>& event) override
{
std::vector<EventHandler> handlers;
{
std::lock_guard<std::mutex> lock(mutex_);
auto it = subscribers_.find(event->getType());
if (it != subscribers_.end())
{
handlers = it->second;
}
}
for (const auto& handler : handlers)
{
try
{
handler(event);
}
catch (const std::exception& e)
{
std::cerr << "Error in event handler: " << e.what() << std::endl;
}
}
}
size_t getSubscriberCount(const std::string& eventType) const override
{
std::lock_guard<std::mutex> lock(mutex_);
auto it = subscribers_.find(eventType);
return it != subscribers_.end() ? it->second.size() : 0;
}
private:
mutable std::mutex mutex_;
std::unordered_map<std::string, std::vector<EventHandler>> subscribers_;
};
// 简单配置管理器实现
class SimpleConfigurationManager : public PluginFramework::IConfigurationManager
{
public:
std::shared_ptr<PluginFramework::IConfiguration>
getPluginConfiguration(const std::string& pluginId) override
{
std::lock_guard<std::mutex> lock(mutex_);
auto it = configurations_.find(pluginId);
if (it != configurations_.end())
{
return it->second;
}
auto config = std::make_shared<JsonConfiguration>(pluginId + ".json");
configurations_[pluginId] = config;
return config;
}
private:
mutable std::mutex mutex_;
std::unordered_map<std::string,
std::shared_ptr<PluginFramework::IConfiguration>> configurations_;
};
// JSON配置实现
class JsonConfiguration : public PluginFramework::IConfiguration
{
public:
JsonConfiguration(const std::string& filePath)
: filePath_(filePath)
{
load(filePath);
}
bool load(const std::string& filePath) override
{
// 实现JSON文件加载
// 使用nlohmann/json或其他JSON库
return true;
}
bool save(const std::string& filePath) override
{
// 实现JSON文件保存
return true;
}
bool hasKey(const std::string& key) const override
{
std::lock_guard<std::mutex> lock(mutex_);
return data_.find(key) != data_.end();
}
std::vector<std::string> getKeys() const override
{
std::lock_guard<std::mutex> lock(mutex_);
std::vector<std::string> keys;
for (const auto& pair : data_)
{
keys.push_back(pair.first);
}
return keys;
}
template<typename T>
T getValue(const std::string& key, const T& defaultValue) const
{
std::lock_guard<std::mutex> lock(mutex_);
auto it = data_.find(key);
if (it != data_.end())
{
try
{
// 类型转换逻辑
return std::any_cast<T>(it->second);
}
catch (const std::bad_any_cast&)
{
return defaultValue;
}
}
return defaultValue;
}
template<typename T>
void setValue(const std::string& key, const T& value)
{
std::lock_guard<std::mutex> lock(mutex_);
data_[key] = value;
}
private:
mutable std::mutex mutex_;
std::string filePath_;
std::unordered_map<std::string, std::any> data_;
};
std::shared_ptr<HostContext> hostContext_;
std::shared_ptr<PluginManager> pluginManager_;
};
}
// 主程序入口
int main(int argc, char* argv[])
{
std::string pluginDirectory = "./plugins";
if (argc > 1)
{
pluginDirectory = argv[1];
}
try
{
PluginHost::HostApplication app;
app.run(pluginDirectory);
return 0;
}
catch (const std::exception& e)
{
std::cerr << "Fatal error: " << e.what() << std::endl;
return 1;
}
}
📊 C# 与 C++ 实现对比
语言特性对比
| 特性 | C# (.NET) | C++ |
|---|---|---|
| 反射机制 | 完整支持,易于插件发现 | 有限支持,需要手动导出函数 |
| 内存管理 | 自动垃圾回收 | 手动内存管理,需要更谨慎 |
| 异常处理 | 结构化异常处理 | 异常处理,但跨DLL边界需小心 |
| 类型安全 | 强类型,运行时检查 | 强类型,编译时检查 |
| 跨平台性 | 优秀的跨平台支持 | 良好,但需要平台特定代码 |
| 热加载 | Assembly.Unload,AppDomain隔离 | 复杂,需要平台特定DLL卸载 |
| 序列化 | 内置强大序列化支持 | 需要第三方库或手动实现 |
实现复杂度对比
csharp
// C# 插件加载(简单)
Assembly assembly = Assembly.LoadFrom("plugin.dll");
var pluginTypes = assembly.GetTypes()
.Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract);
foreach (var type in pluginTypes)
{
var plugin = (IPlugin)Activator.CreateInstance(type);
plugin.Initialize(context);
}
cpp
// C++ 插件加载(复杂)
#ifdef _WIN32
HMODULE handle = LoadLibraryW(L"plugin.dll");
#else
void* handle = dlopen("plugin.so", RTLD_LAZY);
#endif
if (!handle) {
// 错误处理
}
auto createFunc = reinterpret_cast<CreatePluginFunc>(GetProcAddress(handle, "createPlugin"));
auto destroyFunc = reinterpret_cast<DestroyPluginFunc>(GetProcAddress(handle, "destroyPlugin"));
if (!createFunc || !destroyFunc) {
// 错误处理
}
IPlugin* plugin = createFunc();
plugin->initialize(context);
// 卸载时需要
plugin->shutdown();
destroyFunc(plugin);
#ifdef _WIN32
FreeLibrary(handle);
#else
dlclose(handle);
#endif
性能对比
| 指标 | C# (.NET) | C++ |
|---|---|---|
| 启动速度 | 较慢(JIT编译) | 快(原生代码) |
| 运行时性能 | 良好(JIT优化) | 优秀(编译优化) |
| 内存占用 | 较高(包含运行时) | 较低 |
| 插件加载速度 | 快(Assembly加载) | 快(DLL加载) |
| 插件间调用 | 快(托管调用) | 很快(直接调用) |
安全性对比
csharp
// C# 安全性高,支持代码访问安全
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class SandboxedPluginLoader
{
public IPlugin LoadInSandbox(string assemblyPath)
{
var appDomainSetup = new AppDomainSetup
{
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory
};
// 设置权限
var permissionSet = new PermissionSet(PermissionState.None);
permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
var appDomain = AppDomain.CreateDomain(
"Sandbox",
null,
appDomainSetup,
permissionSet);
// 在沙箱中加载插件
var loader = (PluginLoaderProxy)appDomain.CreateInstanceAndUnwrap(
typeof(PluginLoaderProxy).Assembly.FullName,
typeof(PluginLoaderProxy).FullName);
return loader.LoadPlugin(assemblyPath);
}
}
cpp
// C++ 安全性较低,需要额外措施
class SecurePluginLoader
{
public:
std::unique_ptr<IPlugin> loadWithRestrictions(const std::string& path)
{
// 1. 验证插件签名
if (!verifySignature(path)) {
throw std::runtime_error("Invalid plugin signature");
}
// 2. 在独立进程中加载插件(更安全但更复杂)
// 使用进程间通信与插件交互
// 3. 或使用系统安全特性(如Windows的Job Objects)
return std::unique_ptr<IPlugin>(loadPlugin(path));
}
private:
bool verifySignature(const std::string& path)
{
// 使用数字签名验证
// 平台特定实现
return true;
}
};
开发效率对比
csharp
// C# 开发速度快,工具完善
[PluginMetadata("com.example.plugin", "Example Plugin", "1.0.0")]
public class ExamplePlugin : IPlugin, IDisposable
{
// 自动属性,简洁语法
public string Name { get; } = "Example Plugin";
// async/await 支持
public async Task InitializeAsync(IPluginContext context)
{
// LINQ 简化数据处理
var configs = await LoadConfigsAsync();
var validConfigs = configs.Where(c => c.IsValid)
.Select(c => c.Value)
.ToList();
// 丰富的库支持
await ProcessDataAsync(validConfigs);
}
// 自动内存管理
private List<Resource> resources = new List<Resource>();
public void Dispose()
{
// 简洁的资源清理
foreach (var resource in resources)
{
resource.Dispose();
}
}
}
cpp
// C++ 开发更底层,控制更精细
class ExamplePlugin : public IPlugin
{
public:
ExamplePlugin()
: name_("Example Plugin")
, resources_()
{
// 手动资源管理
resources_.reserve(10);
}
~ExamplePlugin()
{
// 必须手动清理
for (auto& resource : resources_)
{
delete resource;
}
}
bool initialize(std::shared_ptr<IPluginContext> context) override
{
// 手动处理异步
auto configs = loadConfigs();
std::vector<ConfigValue> validConfigs;
std::copy_if(configs.begin(), configs.end(),
std::back_inserter(validConfigs),
[](const Config& c) { return c.isValid(); });
// 手动内存管理
auto processor = new DataProcessor();
resources_.push_back(processor);
return processor->process(validConfigs);
}
private:
std::string name_;
std::vector<Resource*> resources_; // 手动管理
};
⚠️ 挑战与注意事项
1. 版本兼容性问题
csharp
// 版本兼容性解决方案
public interface IPluginV2 : IPluginV1
{
// 新功能
Task<PluginResult> ExecuteWithOptionsAsync(ExecutionOptions options);
// 保持向后兼容
new Task ExecuteAsync()
{
return ExecuteWithOptionsAsync(ExecutionOptions.Default);
}
}
// 版本适配器模式
public class PluginVersionAdapter : IPluginV2
{
private readonly IPluginV1 _legacyPlugin;
public PluginVersionAdapter(IPluginV1 legacyPlugin)
{
_legacyPlugin = legacyPlugin;
}
public async Task<PluginResult> ExecuteWithOptionsAsync(ExecutionOptions options)
{
// 将新API适配到旧插件
if (_legacyPlugin is IPluginV2 v2Plugin)
{
return await v2Plugin.ExecuteWithOptionsAsync(options);
}
else
{
// 回退到旧版本行为
await _legacyPlugin.ExecuteAsync();
return PluginResult.Success();
}
}
}
// 插件版本检测
public class VersionCompatibilityChecker
{
public CompatibilityResult CheckCompatibility(
PluginInfo pluginInfo,
Version hostVersion)
{
var pluginVersion = pluginInfo.Version;
// 检查主版本兼容性
if (pluginVersion.Major > hostVersion.Major)
{
return CompatibilityResult.Incompatible(
$"Plugin requires host version {pluginVersion.Major}.x.x");
}
// 检查API兼容性
var apiVersion = GetApiVersion(pluginInfo);
if (!IsApiCompatible(apiVersion))
{
return CompatibilityResult.Incompatible(
$"Plugin uses incompatible API version {apiVersion}");
}
// 检查依赖兼容性
foreach (var dependency in pluginInfo.Dependencies)
{
var depResult = CheckDependencyCompatibility(dependency);
if (!depResult.IsCompatible)
{
return depResult;
}
}
return CompatibilityResult.Compatible();
}
}
2. 安全性挑战
csharp
// 插件安全沙箱
public class PluginSecuritySandbox : MarshalByRefObject
{
private readonly PermissionSet _permissions;
private readonly AppDomain _sandboxDomain;
private readonly List<IPlugin> _loadedPlugins;
public PluginSecuritySandbox()
{
// 定义最小权限集
_permissions = new PermissionSet(PermissionState.None);
_permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
_permissions.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read,
GetTrustedDirectories()));
// 创建沙箱域
var appDomainSetup = new AppDomainSetup
{
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
ApplicationName = "PluginSandbox"
};
_sandboxDomain = AppDomain.CreateDomain(
"PluginSandbox",
null,
appDomainSetup,
_permissions);
_loadedPlugins = new List<IPlugin>();
}
public IPlugin LoadPlugin(string assemblyPath)
{
// 验证插件签名
if (!VerifyPluginSignature(assemblyPath))
{
throw new SecurityException("Plugin signature verification failed");
}
// 在沙箱中加载
var loaderType = typeof(SandboxedPluginLoader);
var loader = (SandboxedPluginLoader)_sandboxDomain.CreateInstanceAndUnwrap(
loaderType.Assembly.FullName,
loaderType.FullName);
var plugin = loader.LoadPlugin(assemblyPath);
_loadedPlugins.Add(plugin);
return plugin;
}
public void ExecutePlugin(string pluginId, object parameters)
{
var plugin = _loadedPlugins.FirstOrDefault(p => p.Id == pluginId);
if (plugin != null)
{
try
{
// 监控插件执行
using (var monitor = new ResourceMonitor())
{
plugin.Execute(parameters);
// 检查资源使用
if (monitor.MemoryUsage > MAX_MEMORY)
{
throw new ResourceLimitExceededException("Memory limit exceeded");
}
}
}
catch (Exception ex)
{
// 隔离插件异常
LogSecurityEvent($"Plugin {pluginId} caused exception: {ex.Message}");
throw new PluginSecurityException("Plugin execution failed", ex);
}
}
}
private bool VerifyPluginSignature(string assemblyPath)
{
// 实现数字签名验证
using (var cert = new X509Certificate2(assemblyPath))
{
// 检查证书有效性
return cert.Verify();
}
}
public void Dispose()
{
foreach (var plugin in _loadedPlugins)
{
try
{
plugin.Dispose();
}
catch (Exception ex)
{
LogSecurityEvent($"Error disposing plugin: {ex.Message}");
}
}
AppDomain.Unload(_sandboxDomain);
}
}
3. 性能优化
csharp
// 插件性能监控与优化
public class PluginPerformanceOptimizer
{
private readonly ConcurrentDictionary<string, PluginPerformanceStats> _stats;
private readonly Timer _monitoringTimer;
public PluginPerformanceOptimizer()
{
_stats = new ConcurrentDictionary<string, PluginPerformanceStats>();
_monitoringTimer = new Timer(MonitorPlugins, null,
TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
}
private void MonitorPlugins(object state)
{
foreach (var kvp in _stats)
{
var pluginId = kvp.Key;
var stats = kvp.Value;
// 检测性能问题
if (stats.AverageExecutionTime > TimeSpan.FromSeconds(1))
{
LogPerformanceWarning($"Plugin {pluginId} is slow: {stats.AverageExecutionTime}");
// 自动优化策略
if (stats.ConcurrentCalls > 1)
{
OptimizeConcurrency(pluginId);
}
if (stats.MemoryUsage > 100 * 1024 * 1024) // 100MB
{
OptimizeMemory(pluginId);
}
}
}
}
private void OptimizeConcurrency(string pluginId)
{
// 实现并发优化策略
// 1. 限制并发调用
// 2. 实现请求队列
// 3. 使用连接池
}
private void OptimizeMemory(string pluginId)
{
// 内存优化策略
// 1. 卸载并重新加载插件
// 2. 清理缓存
// 3. 减少资源保留时间
}
public async Task<T> ExecuteWithOptimization<T>(
string pluginId,
Func<Task<T>> operation)
{
var stopwatch = Stopwatch.StartNew();
var startMemory = GC.GetTotalMemory(false);
try
{
var result = await operation();
var elapsed = stopwatch.Elapsed;
var endMemory = GC.GetTotalMemory(false);
var memoryUsed = Math.Max(0, endMemory - startMemory);
UpdateStats(pluginId, elapsed, memoryUsed, success: true);
return result;
}
catch (Exception ex)
{
UpdateStats(pluginId, stopwatch.Elapsed, 0, success: false);
throw;
}
}
private void UpdateStats(string pluginId, TimeSpan elapsed,
long memoryUsed, bool success)
{
var stats = _stats.GetOrAdd(pluginId,
id => new PluginPerformanceStats());
lock (stats)
{
stats.TotalCalls++;
if (success) stats.SuccessfulCalls++;
stats.TotalExecutionTime += elapsed;
stats.AverageExecutionTime = TimeSpan.FromTicks(
stats.TotalExecutionTime.Ticks / stats.TotalCalls);
stats.MaxMemoryUsage = Math.Max(stats.MaxMemoryUsage, memoryUsed);
stats.AverageMemoryUsage = (stats.AverageMemoryUsage * (stats.TotalCalls - 1)
+ memoryUsed) / stats.TotalCalls;
stats.LastCallTime = DateTime.UtcNow;
}
}
}
4. 依赖管理
csharp
// 高级依赖解析器
public class AdvancedDependencyResolver
{
public class DependencyResolutionResult
{
public bool Success { get; set; }
public List<string> LoadOrder { get; set; }
public List<DependencyConflict> Conflicts { get; set; }
public List<string> MissingDependencies { get; set; }
public void AddConflict(string pluginA, string pluginB,
Version versionA, Version versionB)
{
Conflicts ??= new List<DependencyConflict>();
Conflicts.Add(new DependencyConflict
{
PluginA = pluginA,
PluginB = pluginB,
VersionA = versionA,
VersionB = versionB
});
}
}
public DependencyResolutionResult ResolveDependencies(
IEnumerable<PluginInfo> plugins)
{
var result = new DependencyResolutionResult();
// 构建依赖图
var graph = BuildDependencyGraph(plugins);
// 检测循环依赖
var cycles = DetectCycles(graph);
if (cycles.Any())
{
result.Success = false;
result.Conflicts = cycles.Select(c => new DependencyConflict
{
Type = ConflictType.CircularDependency,
Description = $"Circular dependency: {string.Join(" -> ", c)}"
}).ToList();
return result;
}
// 检测版本冲突
var versionConflicts = DetectVersionConflicts(plugins);
if (versionConflicts.Any())
{
result.Success = false;
result.Conflicts = versionConflicts;
return result;
}
// 拓扑排序
try
{
result.LoadOrder = TopologicalSort(graph);
result.Success = true;
}
catch (InvalidOperationException ex)
{
result.Success = false;
result.Conflicts = new List<DependencyConflict>
{
new DependencyConflict
{
Type = ConflictType.UnresolvableDependency,
Description = ex.Message
}
};
}
return result;
}
private List<List<string>> DetectCycles(Dictionary<string, List<string>> graph)
{
var cycles = new List<List<string>>();
var visited = new HashSet<string>();
var recursionStack = new HashSet<string>();
foreach (var node in graph.Keys)
{
if (!visited.Contains(node))
{
FindCycles(node, graph, visited, recursionStack,
new List<string>(), cycles);
}
}
return cycles;
}
private void FindCycles(string node, Dictionary<string, List<string>> graph,
HashSet<string> visited, HashSet<string> recursionStack,
List<string> path, List<List<string>> cycles)
{
visited.Add(node);
recursionStack.Add(node);
path.Add(node);
if (graph.ContainsKey(node))
{
foreach (var neighbor in graph[node])
{
if (!visited.Contains(neighbor))
{
FindCycles(neighbor, graph, visited, recursionStack, path, cycles);
}
else if (recursionStack.Contains(neighbor))
{
// 找到循环
var cycleStart = path.IndexOf(neighbor);
if (cycleStart >= 0)
{
var cycle = path.Skip(cycleStart).ToList();
cycle.Add(neighbor); // 闭合循环
cycles.Add(cycle);
}
}
}
}
recursionStack.Remove(node);
path.RemoveAt(path.Count - 1);
}
private List<DependencyConflict> DetectVersionConflicts(
IEnumerable<PluginInfo> plugins)
{
var conflicts = new List<DependencyConflict>();
var pluginVersions = plugins.ToDictionary(p => p.Id, p => p.Version);
// 检查直接版本冲突
foreach (var plugin in plugins)
{
foreach (var dependency in plugin.Dependencies)
{
if (pluginVersions.TryGetValue(dependency.PluginId, out var availableVersion))
{
if (dependency.MinVersion > availableVersion ||
(dependency.MaxVersion != null &&
dependency.MaxVersion < availableVersion))
{
conflicts.Add(new DependencyConflict
{
PluginA = plugin.Id,
PluginB = dependency.PluginId,
VersionA = plugin.Version,
VersionB = availableVersion,
Type = ConflictType.VersionMismatch,
Description = $"Plugin {plugin.Id} requires {dependency.PluginId} " +
$"version {dependency.MinVersion}-{dependency.MaxVersion}, " +
$"but found {availableVersion}"
});
}
}
}
}
return conflicts;
}
}
🎯 总结:何时使用插件式架构?
适用场景
-
需要高度可扩展的应用程序
- 内容管理系统(CMS)
- 集成开发环境(IDE)
- 游戏引擎
- 数据分析平台
-
多团队协作开发
- 不同团队负责不同功能模块
- 需要独立开发、测试和部署
-
需要动态功能的系统
- 支持热插拔功能
- 运行时功能扩展
- 模块化更新
-
第三方扩展支持
- 允许第三方开发者扩展功能
- 应用商店或插件市场
不适用场景
-
小型简单应用
- 功能固定,无需扩展
- 开发团队小,沟通成本低
-
性能极端敏感的系统
- 插件调用有额外开销
- 实时性要求极高的系统
-
安全要求极高的环境
- 插件可能引入安全风险
- 如金融交易核心系统
-
资源极度受限的环境
- 嵌入式系统
- 内存和计算资源严格限制
决策矩阵
| 考虑因素 | 适合插件架构 | 不适合插件架构 |
|---|---|---|
| 功能变化频率 | 高频变化 | 低频或不变 |
| 团队规模 | 多个独立团队 | 小型紧密团队 |
| 部署需求 | 独立部署模块 | 整体部署 |
| 技术栈 | 多种技术栈 | 单一技术栈 |
| 维护周期 | 长期维护 | 短期项目 |
| 第三方扩展 | 需要 | 不需要 |
实施建议
-
渐进式采用
阶段1: 定义核心插件接口 阶段2: 将稳定功能重构为插件 阶段3: 实现插件发现和加载机制 阶段4: 添加插件管理功能 阶段5: 开放第三方插件开发 -
工具链建设
- 插件开发SDK
- 插件调试工具
- 插件打包和签名工具
- 插件市场/仓库
-
社区建设
- 开发者文档和教程
- 示例插件库
- 开发者论坛
- 插件审核机制
未来趋势
- 微内核架构演进
- WebAssembly插件系统
- 云原生插件架构
- AI驱动的插件推荐
- 区块链验证的插件安全
插件式架构不仅是技术选择,更是软件设计哲学的体现。它代表着开放、扩展和演化的思想,是现代软件系统应对复杂性和变化的重要武器。无论选择C#、C++还是其他语言,理解插件架构的核心原则并合理应用,都能显著提升软件系统的长期价值。
本文详细探讨了插件式开发的各个方面,从理论基础到具体实现,从C#到C++,从优势到挑战。希望这篇超过10000字的文章能为您的插件式开发实践提供全面而有价值的参考。