动态加载与插件系统的初步实现(二):AppDomain卸载与代理

来源:互联网 发布:java中把实参打印出来 编辑:程序博客网 时间:2024/06/03 19:50

前一篇文章简单展示了类型发现和MEF使用,本文初步进入AppDomain相关内容。

CLR程序运行时会创建默认程序集容器即AppDomain,默认AppDomain不支持卸载其程序集,但CLR支持创建和卸载AppDomain,这意味着我们可以间接地通过额外的AppDomain实现插件的热插拔。

代理AppDomain创建PluginProvider实例,该实例及其发现的IPlugin的实现需要被被默认AppDomain访问,于是发生了跨AppDomain边界的访问,PluginProvider及IPlugin的具体实现需要由MarshalByRefObject派生(更多相关内容仍然需要自行MSDN)。

为Plugin项目添加PluginProxy类,该类负责维护上述的额外AppDomain、将PluginProvider封送回默认AppDomain。本例仅设计了单个插件容器的场景,故以单例模式实现:

public class PluginProxy{    private readonly static PluginProxy instance = new PluginProxy();    private PluginProxy()    {    }    public static PluginProxy Instance    {        get { return instance; }    }    private AppDomain pluginDomain = null;    private PluginProvider pluginProvider = null;    public PluginProvider Provider    {        get        {            if (pluginDomain == null)            {                pluginDomain = AppDomain.CreateDomain("PluginDomain");                Type pluginProviderType = typeof(PluginProvider);                pluginProvider = (PluginProvider)pluginDomain.CreateInstanceAndUnwrap(pluginProviderType.Assembly.FullName, pluginProviderType.FullName);            }            return pluginProvider;        }    }    public void Unload()    {        if (pluginDomain != null)        {            AppDomain.Unload(pluginDomain);            pluginDomain = null;        }    }}
View Code

AppDomain的创建与跨边界访问对象的成本很高,后文中默认AppDomain与插件的交互将以代理PluginProxy通知PluginProvider的方式实现。Plugin中PluginProvider小幅修改:

public class PluginProvider : MarshalByRefObject{    [ImportMany]    public IEnumerable<Lazy<IPlugin>> Plugins { get; private set; }    public PluginProvider()    {        AggregateCatalog catalog = new AggregateCatalog();        catalog.Catalogs.Add(new DirectoryCatalog("."));        CompositionContainer container = new CompositionContainer(catalog);        container.ComposeParts(this);    }}
View Code

MyPlugin1中Plugin1小幅修改:

[Export(typeof(IPlugin))]public class Plugin1 : MarshalByRefObject, IPlugin{    public String DoStuff()    {        return "MyPlugin1 Plugin1.DoStuff";    }}
View Code

主程序PluginProxy由静态类属性访问,同时加入逻辑检验DLL可否在AppDomain卸载后删除,WinForm与WCFRestService示例在后续给出。代码文件

class Program{    static void Main(string[] args)    {        PluginProvider pluginProvider = PluginProxy.Instance.Provider;        foreach (Lazy<IPlugin> plugin in pluginProvider.Plugins)        {            Console.WriteLine(plugin.Value.DoStuff());        }        PluginProxy.Instance.Unload();        String filename = "MyPlugin1.dll";        if (File.Exists(filename))        {            File.Delete(filename);            Console.WriteLine("File deleted");        }        else        {            Console.WriteLine("File not exist");        }        Console.WriteLine("Press Enter to exit");        Console.ReadLine();    }}
View Code

附求职:寻求.Net相关职位,偏向后端,目前人在北京,有意请邮件jusfr.v#gmail.com,请替换#为@,沟通后奉上简历。


<script type="text/javascript"><!--google_ad_client = "ca-pub-1944176156128447";/* cnblogs 首页横幅 */google_ad_slot = "5419468456";google_ad_width = 728;google_ad_height = 90;//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>