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

    以前做了一个在服务器上定时清理文件的 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.如果是较大型复杂的系统中,权限的控制如何实现?

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

原文地址:https://www.cnblogs.com/infozero/p/1779241.html