基于AppDomain的插件开发EMIT通用加载框架(四)

前面我们已经实现了IPlugin接口的插件自动加载。 但是程序使用中,可以不仅仅只有一个接口,而可能是多个接口并存,不能每个接口都手动实现代码类!怎么办?

解决方案是:泛型+EMIT。 使用泛型把自动加载和插件接口分开,使用EMIT自动生成代理类。

如4项目组成:自动加载+接口定义+接口实现+测试程序,如下图:

我们使用的方式上,仍没有什么改变:

private void FormMain_Load(object sender, EventArgs e)

{

//这里加上了泛型参数 IPlugin表示要求自动生成这个接口的代理类

var inst = PluginManager<IPlugin>.Instance;

inst.PluginChanged += OnPluginChanged;

}

void OnPluginChanged(object sender, PluginManagerEventArgs<IPlugin> e)

{

if (e.ChangeType == PluginChangeType.Created)

{

// 这里初始化插件,提供服务

e.PluginInstance.Run(DateTime.Now.ToString());

}

}

当然,最主要的项目就是"PluginLoader"

思路仍是使用RemotePluginLoader加载插件,但此类不再实现IPlugin,而是使用EMIT生成一个插件代理类,该代理类从MarshalByRefObject 继承以支持AppDomain间的通信。

public class RemotePluginLoader<T> : RemoteTypeLoader where T :class

{

protected Type pluginType;

public T Plugin { get; private set; }

protected override System.Reflection.Assembly LoadAssembly(string assemblyPath)

{

var ass = base.LoadAssembly(assemblyPath);

//查找插件

Type typePlugin = typeof(T);

this.pluginType = ass.GetTypes().Where(t => typePlugin.IsAssignableFrom(t)).FirstOrDefault();

//生成代理插件类,并从MarshalByRefObject继承以支持AppDomain通信

this.Plugin = InterfaceProxyBuilder<T>.CreateProxy((T)System.Activator.CreateInstance(pluginType), typeof(MarshalByRefObject));

return ass;

}

/// <summary>

///直接在远程Domain中,执行方法。要求支持序列化

/// </summary>

/// <param name="action">执行的匿名方法</param>

public void Execute(Action action)

{

action();

}

/// <summary>

///直接在远程Domain中,执行函数。要求支持序列化

/// </summary>

/// <typeparam name="T"></typeparam>

/// <param name="fun"></param>

/// <returns></returns>

public T Execute<T>(Func<T> fun)

{

return fun();

}

在调用方,基于插件更新时,我们要求统一更新引用,也有生成一个代理类。 所不同的是,该代理类每次都要访问函数,从而每次都可以检查插件的情况并进行控制:

public class PluginCallerProxy<T> where T : class

{

private T _targetPlugin;

private T _proxyPlugin;

private PluginLoader<T> _pluginLoader;

private System.Threading.ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

/// <summary>

///构造一个代理类,保存在 ProxyPlugin 属性中

/// </summary>

/// <param name="loader"></param>

public PluginCallerProxy(PluginLoader<T> loader)

{

this.PluginLoader = loader;

this.TargetPlugin = loader.Plugin;

//从函数生成代理类

this._proxyPlugin = InterfaceProxyBuilder<T>.CreateFuncProxy(() => this.TargetPlugin, typeof(object));

}

/// <summary>

///供使用的代理

/// </summary>

public T ProxyPlugin

{

get { return _proxyPlugin; }

}

#region实现

internal PluginLoader<T> PluginLoader

{

get

{

return _pluginLoader;

}

set

{

_pluginLoader = value;

this.TargetPlugin = _pluginLoader == null ? null : _pluginLoader.Plugin;

}

}

internal T TargetPlugin

{

get

{

locker.EnterReadLock();

try

{

if (_targetPlugin == null)

{

throw new PluginException("插件已经卸载");

}

return _targetPlugin;

}

finally

{

locker.ExitReadLock();

}

}

set

{

locker.EnterWriteLock();

try

{

_targetPlugin = value;

}

finally

{

locker.ExitWriteLock();

}

}

}

#endregion

}

最终得到新的插件管理类,代码如下:

public class PluginManager<T> where T : class

{

#region实现

#region字段

private static PluginManager<T> _instance = null;

private FileSystemWatcher pluginWatcher;

private Timer timerProcess = null;

private ConcurrentDictionary<string, FileSystemEventArgs> changedPlugins = new ConcurrentDictionary<string, FileSystemEventArgs>();

private ConcurrentDictionary<string, PluginCallerProxy<T>> plugins = new ConcurrentDictionary<string, PluginCallerProxy<T>>();

#endregion

static PluginManager()

{

if (_instance == null)

{

lock (typeof(PluginManager<T>))

{

if (_instance == null)

_instance = new PluginManager<T>();

}

}

}

private PluginManager()

{

string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");

//监控

this.pluginWatcher = new FileSystemWatcher(path, "*.dll");

this.pluginWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;

this.pluginWatcher.Changed += OnPluginChanged;

this.pluginWatcher.Created += OnPluginChanged;

this.pluginWatcher.Deleted += OnPluginChanged;

this.pluginWatcher.Renamed += OnPluginRenamed;

pluginWatcher.EnableRaisingEvents = true;

timerProcess = new Timer(new TimerCallback(e => this.ProcessChangedPlugin()));

//加载所有

Directory.GetFiles(path, "*.dll").ToList().ForEach(file =>

{

FileInfo fi = new FileInfo(file);

this.changedPlugins[fi.Name] = new FileSystemEventArgs(WatcherChangeTypes.Created, fi.DirectoryName, fi.Name);

});

this.timerProcess.Change(10, -1);

}

void OnPluginRenamed(object sender, RenamedEventArgs e)

{

//重命名,理解为去掉原来的,增加新命名的

FileInfo old = new FileInfo(e.OldFullPath);

this.changedPlugins[old.Name] = new FileSystemEventArgs(WatcherChangeTypes.Deleted, old.DirectoryName, old.Name);

FileInfo n = new FileInfo(e.FullPath);

this.changedPlugins[n.Name] = new FileSystemEventArgs(WatcherChangeTypes.Created, n.DirectoryName, n.Name);

//1秒后再处理

this.timerProcess.Change(1000, -1);

}

void OnPluginChanged(object sender, FileSystemEventArgs e)

{

Debug.Print(e.Name + e.ChangeType);

//记录变更

this.changedPlugins[e.Name] = e;

//1秒后再处理

this.timerProcess.Change(1000, -1);

}

protected void ProcessChangedPlugin()

{

#region处理插件变化

foreach (var kv in this.changedPlugins)

{

FileSystemEventArgs e;

if (changedPlugins.TryRemove(kv.Key, out e))

{

Debug.Print(e.Name + "=>" + e.ChangeType);

switch (e.ChangeType)

{

case WatcherChangeTypes.Created:

{

//加载

var loader = new PluginLoader<T>(e.Name);

var proxy = new PluginCallerProxy<T>(loader);

plugins.TryAdd(e.Name, proxy);

OnPluginChange(new PluginManagerEventArgs<T>(e.Name, PluginChangeType.Created, proxy.ProxyPlugin));

}

break;

case WatcherChangeTypes.Deleted:

{

PluginCallerProxy<T> proxy;

if (plugins.TryRemove(e.Name, out proxy))

{

OnPluginChange(new PluginManagerEventArgs<T>(e.Name, PluginChangeType.Deleted, proxy.ProxyPlugin));

var loader = proxy.PluginLoader;

proxy.PluginLoader = null;

loader.Unload();

}

}

break;

case WatcherChangeTypes.Changed:

{

PluginCallerProxy<T> proxy;

if (plugins.TryGetValue(e.Name, out proxy))

{

OnPluginChange(new PluginManagerEventArgs<T>(e.Name, PluginChangeType.Deleted, proxy.ProxyPlugin));

var loader = proxy.PluginLoader;

loader.Unload();

loader = new PluginLoader<T>(e.Name);

proxy.PluginLoader = loader;

OnPluginChange(new PluginManagerEventArgs<T>(e.Name, PluginChangeType.Created, proxy.ProxyPlugin));

}

}

break;

}

}

}

#endregion

}

protected virtual void OnPluginChange(PluginManagerEventArgs<T> e)

{

if (PluginChanged != null)

{

PluginChanged(this, e);

}

}

#endregion

#region公共

public static PluginManager<T> Instance

{

get

{

return _instance;

}

}

public event PluginChangeHandle<T> PluginChanged;

#endregion

}

附:

  1. EMIT代理生成

/// <summary>

///从接口 TPlugin 生成代理类

/// </summary>

/// <typeparam name="TPlugin">要求是一个接口</typeparam>

public static class InterfaceProxyBuilder<TPlugin> where TPlugin : class

{

private static ConcurrentDictionary<Type, Type> proxies = new ConcurrentDictionary<Type, Type>();

private static void CheckTargetType(Type targetType)

{

if (!targetType.IsInterface)

{

throw new NotImplementedException("T 必须为接口");

}

}

/// <summary>

///生成接口实例对像的代理

/// </summary>

/// <typeparam name="TObject"></typeparam>

/// <param name="target"></param>

/// <returns></returns>

public static TPlugin CreateProxy<TObject>(TObject target, Type baseType) where TObject : TPlugin

{

Type targetType =typeof(TPlugin);

CheckTargetType(targetType);

var proxyType = proxies.GetOrAdd(targetType, t =>

{

return CreateProxyType(t, baseType);

});

return System.Activator.CreateInstance(proxyType, target) as TPlugin;

}

/// <summary>

///生成一个接口的代理类,并从baseType继承

/// </summary>

/// <param name="targetType">接口类型</param>

/// <param name="baseType">基类</param>

/// <returns>代理类</returns>

public static Type CreateProxyType(Type targetType, Type baseType)

{

Debug.Assert(targetType.IsInterface,"必须是接口");

string typeName = string.Concat(targetType.FullName, "_Proxy");

AssemblyName assemblyName = new AssemblyName("DynamicAssembly");

AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

var module = assemblyBuilder.DefineDynamicModule("DynamicProxy", "DynamicAssembly.dll");

//声明类

var typeBuilder = module.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed, baseType, new Type[] { targetType }); //

//实现类

//字段

var fieldBuilder = typeBuilder.DefineField("target", targetType, FieldAttributes.Private);

fieldBuilder.SetConstant(null);

//构造函数

var cnstBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { targetType });

{

var il = cnstBuilder.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);

il.Emit(OpCodes.Ldarg_1);

il.Emit(OpCodes.Stfld, fieldBuilder);

il.Emit(OpCodes.Ret);

}

//属性

Dictionary<MethodInfo, MethodBuilder> map = new Dictionary<MethodInfo, MethodBuilder>();

//方法代理

var methods = targetType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

methods.ToList().ForEach(mi =>

{

var retType = mi.ReturnType;

var parmTypes = mi.GetParameters().ToList().ConvertAll(pi => pi.ParameterType).ToArray();

MethodAttributes methodAttrs = mi.Attributes & (~MethodAttributes.Abstract);

var methodBuilder = typeBuilder.DefineMethod(mi.Name, methodAttrs, CallingConventions.Standard, mi.ReturnType, parmTypes);

//方法体

{

var il = methodBuilder.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);

il.Emit(OpCodes.Ldfld, fieldBuilder);

if (parmTypes.Length > 0)

{

for (int i = 1; i <= parmTypes.Length; ++i)

{

switch (i)

{

case 0:

il.Emit(OpCodes.Ldarg_0);

break;

case 1:

il.Emit(OpCodes.Ldarg_1);

break;

case 2:

il.Emit(OpCodes.Ldarg_2);

break;

case 3:

il.Emit(OpCodes.Ldarg_3);

break;

default:

il.Emit(OpCodes.Ldarg_S, i);

break;

}

}

}

il.Emit(OpCodes.Callvirt, mi);

if (mi.ReturnType == typeof(void))

{

il.Emit(OpCodes.Pop);

}

il.Emit(OpCodes.Ret);

}

map.Add(mi, methodBuilder);

});

var props = targetType.GetProperties();

props.ToList().ForEach(pi =>

{

var propBuilder = typeBuilder.DefineProperty(pi.Name, PropertyAttributes.HasDefault, pi.ReflectedType, null);

if (pi.CanRead)

{

var mi = pi.GetGetMethod();

Debug.Assert(map.ContainsKey(mi));

var builder = map[mi];

propBuilder.SetGetMethod(builder);

}

if (pi.CanWrite)

{

var mi = pi.GetSetMethod();

Debug.Assert(map.ContainsKey(mi));

var builder = map[mi];

propBuilder.SetSetMethod(builder);

}

});

var ret = typeBuilder.CreateType();

#if DEBUG

assemblyBuilder.Save(string.Concat(typeName, "_", DateTime.Now.ToString("yyyyMMddHHmmss") , ".dll"));

#endif

return ret;

}

public static TPlugin CreateFuncProxy(Func<TPlugin> targetFunc, Type baseType)

{

Type targetType = typeof(TPlugin);

CheckTargetType(targetType);

var proxyType = proxies.GetOrAdd(typeof(Func<TPlugin>), t =>

{

return CreateFuncProxyType(t, baseType);

});

return System.Activator.CreateInstance(proxyType, targetFunc) as TPlugin;

}

/// <summary>

///生成一个接口工厂的代理类,并从baseType继承

/// </summary>

/// <param name="targetType">接口工厂类型要求必须为 Func&lt;TPlugin&gt;</param>

/// <param name="baseType">基类</param>

/// <returns>代理类</returns>

public static Type CreateFuncProxyType(Type targetType, Type baseType)

{

var miInvoke = targetType.GetMethod("Invoke");

Debug.Assert(miInvoke != null, "Func<T>.Invoke 必须有");

Type interfaceType = miInvoke.ReturnType;

string typeName = string.Concat(interfaceType.FullName, "_FuncProxy");

AssemblyName assemblyName = new AssemblyName("DynamicAssembly");

AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

var module = assemblyBuilder.DefineDynamicModule("DynamicProxy", "DynamicAssembly.dll");

//声明类

var typeBuilder = module.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed, baseType, new Type[] { interfaceType }); //

//实现类

//字段

var fieldBuilder = typeBuilder.DefineField("targetFunc", targetType, FieldAttributes.Private);

fieldBuilder.SetConstant(null);

//构造函数

var cnstBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { targetType });

{

var il = cnstBuilder.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);

il.Emit(OpCodes.Ldarg_1);

il.Emit(OpCodes.Stfld, fieldBuilder);

il.Emit(OpCodes.Ret);

}

//属性

Dictionary<MethodInfo, MethodBuilder> map = new Dictionary<MethodInfo, MethodBuilder>();

//方法代理

var methods = interfaceType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

methods.ToList().ForEach(mi =>

{

var retType = mi.ReturnType;

var parmTypes = mi.GetParameters().ToList().ConvertAll(pi => pi.ParameterType).ToArray();

MethodAttributes methodAttrs = mi.Attributes & (~MethodAttributes.Abstract);

var methodBuilder = typeBuilder.DefineMethod(mi.Name, methodAttrs, CallingConventions.Standard, mi.ReturnType, parmTypes);

//方法体

{

var il = methodBuilder.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);

il.Emit(OpCodes.Ldfld, fieldBuilder);

il.Emit(OpCodes.Callvirt, miInvoke);

if (parmTypes.Length > 0)

{

for (int i = 1; i <= parmTypes.Length; ++i)

{

switch (i)

{

case 0:

il.Emit(OpCodes.Ldarg_0);

break;

case 1:

il.Emit(OpCodes.Ldarg_1);

break;

case 2:

il.Emit(OpCodes.Ldarg_2);

break;

case 3:

il.Emit(OpCodes.Ldarg_3);

break;

default:

il.Emit(OpCodes.Ldarg_S, i);

break;

}

}

}

il.Emit(OpCodes.Callvirt, mi);

if (mi.ReturnType == typeof(void))

{

il.Emit(OpCodes.Pop);

}

il.Emit(OpCodes.Ret);

}

map.Add(mi, methodBuilder);

});

var props = interfaceType.GetProperties();

props.ToList().ForEach(pi =>

{

var propBuilder = typeBuilder.DefineProperty(pi.Name, PropertyAttributes.HasDefault, pi.ReflectedType, null);

if (pi.CanRead)

{

var mi = pi.GetGetMethod();

Debug.Assert(map.ContainsKey(mi));

var builder = map[mi];

propBuilder.SetGetMethod(builder);

}

if (pi.CanWrite)

{

var mi = pi.GetSetMethod();

Debug.Assert(map.ContainsKey(mi));

var builder = map[mi];

propBuilder.SetSetMethod(builder);

}

});

var ret = typeBuilder.CreateType();

#if DEBUG

assemblyBuilder.Save(string.Concat(typeName, "_Func_", DateTime.Now.ToString("yyyyMMddHHmmss"), ".dll"));

#endif

return ret;

}

}

 

2. 项目类关系图:

原文地址:https://www.cnblogs.com/evlon/p/emt_plugin.html