zoukankan      html  css  js  c++  java
  • 动态加载与插件系统的初步实现(二):AppDomain卸载与代理

    前一篇文章简单展示了类型发现和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;
            }
        }
    }

    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);
        }
    }

    MyPlugin1中Plugin1小幅修改:

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

    主程序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();
        }
    }

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

  • 相关阅读:
    常见SQL语句
    测试用例的设计
    移动端测试注意事项
    markdown编辑模式基本使用
    常用修改请求或返回方法
    前端性能测试工具Lighthouse
    presto环境部署
    pyenv管理python版本
    python2.6.6升级python2.7.14
    InfluxDB权限认证机制
  • 原文地址:https://www.cnblogs.com/Jusfr/p/3149852.html
Copyright © 2011-2022 走看看