Add XCode skills for entity caching, ORM, and sharding ETL
|
---
name: plugin-framework
description: >
使用 NewLife.Core çš„ IPlugin / PluginManager 构建应用内æ’件系统:
定义æ’件接å£ã€é€šè¿‡ PluginAttribute æ ‡è®°å®¿ä¸»ã€ç”¨ PluginManager 扫æ/åŠ è½½/åˆå§‹åŒ–/é”€æ¯æ’件。
适用于功能扩展点ã€äº‹ä»¶ç›‘å¬å™¨æ³¨å†Œã€å¯æ‹”æ’æ¨¡å—ç‰åœºæ™¯ã€‚
argument-hint: >
è¯´æ˜Žä½ çš„åœºæ™¯ï¼šå®¿ä¸»æ ‡è¯†æ˜¯ä»€ä¹ˆï¼ˆIdentity);æ’件需è¦å®žçŽ°å“ªäº›é™„åŠ æŽ¥å£ï¼ˆå¦‚ IDataProcessor);
是å¦éœ€è¦ä¾èµ–注入(IServiceProviderï¼‰èŽ·å–æœåŠ¡ï¼›
æ’件是å¦éœ€è¦ Dispose(倒åºé”€æ¯ï¼‰ã€‚
---
# æ’件框架技能(IPlugin + PluginManager)
## 适用场景
- 宿主程åºå®šä¹‰æ‰©å±•点接å£ï¼ˆå¦‚ `IDataProcessor`),æ’件程åºé›†å®žçްåŽé€šè¿‡æ‰«æè‡ªåŠ¨åŠ è½½ã€‚
- 模å—化架构:å„功能模å—以æ’件形弿Œ‚è½½åˆ°å®¿ä¸»ï¼Œè§£è€¦æ ¸å¿ƒä¸Žæ‰©å±•é€»è¾‘ã€‚
- 事件监å¬å™¨åˆ†å‘:宿主é历 `Plugins.OfType<IEventListener>()` 通知所有监å¬å™¨ã€‚
- 代ç 审查:确认 `PluginManager.Dispose()` åœ¨å®¿ä¸»å…³é—æ—¶è°ƒç”¨ï¼ˆå€’åºé‡Šæ”¾å„æ’ä»¶ `IDisposable`);`Init()` 返回 `false` çš„æ’件会被自动移除。
## æ ¸å¿ƒåŽŸåˆ™
1. **`Init()` 决定留å˜**:æ’ä»¶çš„ `Init` 返回 `true` æ‰è¢«ä¿ç•™ï¼›`false` 表示"ä¸é€‚用本宿主",立å³ä»Ž `Plugins` ä¸ç§»é™¤ã€‚
2. **`[Plugin("Identity")]` 是过滤器**:`Load()` æ—¶åªåŠ è½½å¸¦æœ‰ä¸Žå®¿ä¸» `Identity` 匹é…çš„ `PluginAttribute` çš„ç±»åž‹ï¼ˆæˆ–æ— è¯¥ Attribute çš„ç±»åž‹ä¹Ÿä¼šè¢«åŠ è½½ï¼Œåœ¨ `Init` ä¸è‡ªè¡Œåˆ¤æ–)。
3. **`IServiceProvider` 在 `Init` 䏿³¨å…¥ä¾èµ–**:æ’ä»¶æž„é€ å‡½æ•°æ— æ³•èŽ·å–æœåŠ¡ï¼›åœ¨ `Init(identity, provider)` ä¸é€šè¿‡ `provider.GetService<T>()` 获å–ä¾èµ–。
4. **å€’åº Dispose**:`PluginManager.Dispose()` æŒ‰åŠ è½½é€†åºè°ƒç”¨å„ `IDisposable` æ’ä»¶çš„ `Dispose()`,确ä¿ä¾èµ–é¡ºåºæ£ç¡®é‡Šæ”¾ã€‚
5. **所有程åºé›†æ‰«æ**:`Load()` 扫æ AppDomain 䏿‰€æœ‰å·²åŠ è½½ç¨‹åºé›†ï¼Œæ’ä»¶åªéœ€åœ¨é¡¹ç›®ä¸å¼•用å³å¯è‡ªåЍå‘现。
## 执行æ¥éª¤
### 一ã€å®šä¹‰æ’件接å£ä¸Žå®žçް
```csharp
using NewLife.Model;
// 1. 定义扩展点接å£ï¼ˆå¯é€‰ï¼Œå®¿ä¸»é€šè¿‡æ¤æŽ¥å£è°ƒç”¨æ’件)
public interface IDataProcessor
{
string Name { get; }
void Process(object data);
}
// 2. 实现æ’件([Plugin] æ ‡è®°å®¿ä¸» Identity)
[Plugin("DataPipeline")] // åªåœ¨ "DataPipeline" 宿主ä¸åŠ è½½
public class JsonProcessor : IPlugin, IDataProcessor
{
public string Name => "JSON处ç†å™¨";
private ILogger? _logger;
// æž„é€ å‡½æ•°ï¼šå®¿ä¸»åŠ è½½æ—¶è°ƒç”¨ï¼ˆæ¤æ—¶æ— æœåŠ¡æ³¨å…¥ï¼‰
public JsonProcessor() { }
// Init:宿主åˆå§‹åŒ–时调用,provider å¯èŽ·å–ä¾èµ–æœåŠ¡
public bool Init(string? identity, IServiceProvider provider)
{
// éžç›®æ ‡å®¿ä¸»åˆ™æ‹’ç»ï¼ŒPluginManager ä¼šç§»é™¤æ¤æ’ä»¶
if (identity != "DataPipeline") return false;
_logger = provider.GetService<ILogger>();
_logger?.Info("JsonProcessor åˆå§‹åŒ–");
return true;
}
public void Process(object data)
{
var json = data.ToJson();
_logger?.Info("处ç†JSON: {0}", json);
}
}
// 3. 支æŒå¤šå®¿ä¸»ï¼ˆå¤šä¸ª PluginAttribute)
[Plugin("WebServer")]
[Plugin("ApiServer")]
public class AuthPlugin : IPlugin
{
public bool Init(string? identity, IServiceProvider provider) => true;
}
```
### 二ã€å®¿ä¸»åŠ è½½æ’ä»¶
```csharp
using NewLife.Model;
using NewLife.Log;
// 创建æ’件管ç†å™¨
var manager = new PluginManager
{
Identity = "DataPipeline", // å®¿ä¸»æ ‡è¯†ï¼Œä¸Ž PluginAttribute 匹é…
Provider = ObjectContainer.Provider, // æœåŠ¡å®¹å™¨ï¼Œä¼ é€’ç»™ Plugin.Init()
Log = XTrace.Log,
};
// æ‰«ææ‰€æœ‰å·²åŠ è½½ç¨‹åºé›†ï¼Œå‘现并实例化 IPlugin 实现
manager.Load();
// 便¬¡è°ƒç”¨ Init(),移除返回 false çš„æ’ä»¶
manager.Init();
// æŸ¥çœ‹å·²åŠ è½½çš„æ’ä»¶
foreach (var plugin in manager.Plugins ?? Array.Empty<IPlugin>())
{
XTrace.WriteLine("å·²åŠ è½½æ’ä»¶: {0}", plugin.GetType().Name);
}
// å®¿ä¸»å…³é—æ—¶é‡Šæ”¾ï¼ˆå€’åº Dispose)
manager.Dispose();
```
### 三ã€é€šè¿‡æ‰©å±•接å£ä½¿ç”¨æ’ä»¶
```csharp
// é历实现了特定扩展接å£çš„æ’ä»¶
foreach (var processor in manager.Plugins?.OfType<IDataProcessor>() ?? Enumerable.Empty<IDataProcessor>())
{
processor.Process(myData);
}
// äº‹ä»¶ç›‘å¬æ¨¡å¼
public void RaiseEvent(string eventName, object? args)
{
foreach (var listener in manager.Plugins?.OfType<IEventListener>() ?? Enumerable.Empty<IEventListener>())
{
listener.OnEvent(eventName, args);
}
}
```
### å››ã€å¸¦ç”Ÿå‘½å‘¨æœŸçš„æ’ä»¶ï¼ˆDispose)
```csharp
[Plugin("MyApp")]
public class ResourcePlugin : IPlugin, IDisposable
{
private Timer? _timer;
public bool Init(string? identity, IServiceProvider provider)
{
if (identity != "MyApp") return false;
// å¯åŠ¨å†…éƒ¨èµ„æº
_timer = new Timer(OnTick, null, 0, 5000);
return true;
}
private void OnTick(object? state) { /* 定期任务 */ }
public void Dispose()
{
_timer?.Dispose();
_timer = null;
XTrace.WriteLine("ResourcePlugin 已释放");
}
}
// PluginManager.Dispose() 会倒åºè°ƒç”¨å„æ’ä»¶çš„ Dispose()
```
### 五ã€ä»…èŽ·å–æ’件类型(ä¸å®žä¾‹åŒ–)
```csharp
// èŽ·å–æ‰€æœ‰åŒ¹é…çš„æ’件类型,自定义实例化逻辑
foreach (var type in manager.LoadPlugins())
{
XTrace.WriteLine("å‘现æ’件类型: {0}", type.FullName);
// 自定义实例化...
}
```
## é‡ç‚¹æ£€æŸ¥é¡¹
- [ ] å®¿ä¸»å…³é—æ—¶æ˜¯å¦è°ƒç”¨äº† `manager.Dispose()`ï¼ˆç¡®ä¿æ’件倒åºé‡Šæ”¾ï¼‰ï¼Ÿ
- [ ] æ’ä»¶ `Init()` 是å¦åœ¨ `identity` ä¸åŒ¹é…时返回 `false`(é¿å…æ— å…³å®¿ä¸»è¯¯åŠ è½½ï¼‰ï¼Ÿ
- [ ] æ’件是å¦åœ¨ `Init()` ä¸èŽ·å–æœåŠ¡ä¾èµ–ï¼ˆè€Œä¸æ˜¯æž„é€ å‡½æ•°ï¼Œæž„é€ å‡½æ•°æ—¶ `IServiceProvider` è¿˜æœªä¼ å…¥ï¼‰ï¼Ÿ
- [ ] 实现了 `IDisposable` çš„æ’件是å¦ä¸åœ¨ `Init` 外部缓å˜èµ„æºï¼ˆDispose åœ¨å®¿ä¸»å…³é—æ—¶æ‰è°ƒç”¨ï¼‰ï¼Ÿ
- [ ] `PluginAttribute` æ ‡è®°çš„ Identity 是å¦ä¸Ž `PluginManager.Identity` 大å°å†™ä¸€è‡´ï¼ˆå—符串比较)?
## è¾“å‡ºè¦æ±‚
- **æ’件接å£**:`IPlugin`(`NewLife.Model`)—— `Init(identity, provider)` 返回 bool。
- **æ ‡è®°ç‰¹æ€§**:`[Plugin("HostIdentity")]`,支æŒé‡å¤æ ‡æ³¨å¤šä¸ªå®¿ä¸»ã€‚
- **管ç†å™¨**:`PluginManager`(`NewLife.Model`)—— `Load()`/`Init()`/`Dispose()`ï¼›`Identity`/`Provider`/`Plugins`。
- **生命周期**:æ’ä»¶å¯å®žçް `IDisposable`ï¼›`PluginManager.Dispose()` 倒åºè°ƒç”¨ã€‚
## å‚考资料
- `NewLife.Core/Model/IPlugin.cs`
- `NewLife.Core/Model/PluginManager.cs`
- 相关技能:`dependency-injection-ioc`(`ObjectContainer.Provider` ä¼ é€’ç»™ PluginManager)ã€`hosted-services-lifecycle`(æ’ä»¶éšå®¿ä¸»æœåŠ¡ä¸€èµ·å¯åœï¼‰
|