• 利用反射做插件式系统的一次实践


        以前做了一个在服务器上定时清理文件的 Console App - 通过任务计划的方式运行。前不久又因为一个需求:每隔一段时间要自动生成某些 JS 文件,这两个站点放在同一个服务器上,任务计划的执行时间也是一样,加之之前一直在琢磨着怎么样做一个插件式系统,于是我决定试一下。 
        一个原则:主系统不依赖于子系统,子系统依赖于主系统---也就是说主系统不知道你子系统要干什么。
        我的思路:通过配置文件,在主程序里定义一个接口 IPlugin,通过配置文件 + 反射得到接口的实例的方式实现。有了思路,先上图看看我建的工程样子:


    其中: CS.Project 是将执行的主程序; CS.Plugins.FileApp 和 CS.Plugs.ForHtml 分别是A站点的文件清理程序和 B站点的 Html/JS 文件的生成程序,它们是插件。
    主站点的 IPlugin 的定义如下:
    IPlugin
    namespace CS.Project
    {
        
    /*************************************
         * 插件所必须实现的接口
         * **********************************
    */
        
    public interface IPlugin
        {
            
    void Execute();
        }
    }

     CS.Plugins.FileApp 的 FileClean 和 CS.Plugs.ForHtml 的 CreateHtml 工程里需分别实现这个接口。

    FileClean 文件清理
    using System;
    using CS.Project;

    namespace CS.Plugins.FileApp
    {
        
    /*********************************
         * 文件清理
         * ******************************
    */
        
    public class FileClean : IPlugin
        {
            
    public FileClean() {
                Write(
    "CS.Plugins.FileClean 被创建");
            }

            
    public void Execute() {
                Write(
    "CS.Plugins.FileClean.Execute 将被执行 ");
            }
            
    private void Write(string msg) {
                Console.WriteLine(
    "ProId: {0} , {1}", AppDomain.CurrentDomain.Id, msg);
            }
        }
    }

    CreateHtml 创建 JS 及 HTML 文件

    using System;
    using CS.Project;
    namespace CS.Plugs.ForHtml
    {
        
    /*****************************************
         * 创建 JS 及 HTML 文件
         * *************************************
    */
        
    public class CreateHtml : IPlugin
        {
            
    public CreateHtml() {
                Write(
    "CS.Plugs.ForHtml.CreateHtml 实例创建");
            }

            
    public void Execute() {
                Write(
    "CS.Plugs.ForHtml.Execute 方法执行 ");        
            }
            
    private void Write(string msg) {
                Console.WriteLine(
    "ProId: {0} , {1}", AppDomain.CurrentDomain.Id, msg);
            }
        }
    }


    最后,配置文件如下:

    Plugs.xml 配置文件
    <?xml version="1.0" encoding="utf-8" ?>
    <Plugins>
      
    <add Assembly="CS.Plugins.FileApp" PluginsName="CS.Plugins.FileApp.FileClean" />
      
    <add Assembly="CS.Plugs.ForHtml" PluginsName="CS.Plugs.ForHtml.CreateHtml" />
    </Plugins>


    主程序如下:

    主程序
    using System;
    using System.Reflection;
    using System.Linq;
    using System.Xml.Linq;

    namespace CS.Project
    {
        
    internal class Program
        {
            
    static void Main(string[] args)
            {
                doWork();
                Console.ReadKey();
            }

            
    static void doWork() {
                
    // 从 配置文件 中读取相关 
                XDocument doc = XDocument.Load("Plugs.xml");
                var plugs 
    = from config in doc.Descendants("Plugins").Elements("add")
                            select 
    new
                            {
                                assemblyName 
    = config.Attribute("Assembly"),
                                PluginsName 
    = config.Attribute("PluginsName")
                            };
                
    foreach (var item in plugs)
                {
                    Assembly assembly 
    = Assembly.Load(item.assemblyName.Value);
                    IPlugin instance = assembly.CreateInstance(item.PluginsName.Value) as IPlugin;
                    //根据配置文件获取实例,这与以下获取实例的方法相同
                    //Type type = assembly.GetType(item.PluginsName.Value);
                    //IPlugin instance = Activator.CreateInstance(type) as IPlugin;

                    
    if (instance != null)
                        instance.Execute();
                }
            }

        }
    }


    编译,运行,其结果如下:


    Oh, Yeah! 成功了!

    后续的几点思考:
    1. 多线程场景下如何实现;
    2.如果是较大型复杂的系统中,权限的控制如何实现?

    我的一点体会: 插件式系统方式的开发在后续的开发中应该逐渐地会成为主流, 在业务系统的开发中挺考验人的。

  • 相关阅读:
    yolov3计算mAP
    ESP32 ADC的坑
    DCNv2编译过程报错:error: identifier "THCudaBlas_SgemmBatched" is undefined
    Arduino在Lib中输出调试参数
    ESP32获取WT901CTTL/232四元数
    常用公共前端CDN库
    js / php 网站底部版权文字自动改变年份
    以管理员身份在当前目录打开命令行窗口
    【JavaScript】提取字符串里的分数,及计算平均分并与平均分比较输出
    添加谷歌翻译到你的网站
  • 原文地址:https://www.cnblogs.com/infozero/p/1779241.html
Copyright © 2020-2023  润新知