JCreator

博客园 首页 联系 订阅 管理

    4.3插件平台动态装载DLL并执行

     PlugFramework是整个PlugPlatform平台的核心内容。主要实现检查和装载DLL文件,动态创建实例化对象,验证并执行外部方法。

                                        

                                                                 图8  PlugPlatform动态装载的全过程

     PlugPlatform依据配置文件可以了解装载的外部DLL文件和要求执行的类或接口方法。整个装载和的调用过程如图8说明。

 

   PlugFramework包含有类和接口,这些类和接口之间有继承、实现、关联关系。其类图如图9所示。

                                                 

                                                                    图9 PlugPlatform类图 

    PlugFramework各个类的具体详细描述如下: 

1.Plus.PlusConfig     
插件平台的配置信息类,可创建工厂类    
2.Plus.PlugFactory 
插件平台的工厂类,可以创建方法实现类  
3.Plus.IAction     
方法实现的接口                      接口
4.Plus.Framework.PlugAction 
方法实现的抽象祖先类                      
5.Plus.Framework.ClassAction
类对象的实现类                        类
6.Plus.Framework.InterfaceAction    
接口对象的实现类                      类          
7.Plus.Framework.AssemblyManager
Assembly的管理类,生成Assembly        
8.Plus.Framework.TypeManager
Type的管理类,可实现对Type、Object的生成和检查。包括动态方法的调用。                          类
动态调用外部方法的核心代码如下所示: 
public object InvokeClassMethod(String className, object[] objectArgs, String methodName, object[] methodArgs)


   Object[] newArgs = new Object[methodArgs.Length];
 
   Object thisObject = new Object();
 
   Type type = CreateType(className);
 
   MethodInfo[] methods = type.GetMethods();
 
   Object instance = CreateObject(type, objectArgs);
 
   foreach(MethodInfo m in methods) 
     {
 
     if(m.Name == methodName) 
          {
       newArgs = ConvertArgsType(m, methodArgs);
       try 
              {
          if(!m.IsStatic) 
                    {
                       thisObject = m.Invoke(instance, newArgs);//非静态方法,使用类实例调用
                    } 
          else 
                    {
                        thisObject = m.Invoke(null, newArgs);
                    }
           return thisObject;
             }
       catch(Exception e)
             {
                  throw new PlusException("不能动态调用方法,原因:" + e.Message, e); 
             }
          }
 
   }
     return thisObject;
}

图10表示PlugPlatform实现全过程。

下面分别对每个步骤做一个详细描述:

  ① 外部应用请求动态调用。

  ② PlusConfig类根据配置文件创建PlugFactory对象。

  ③ PlugFactory对象创建一个Action对象。

  ④ Action对象获得MethodObject对象组,逆向产生DllFileObject对象。

  ⑤ 根据DllFileObject对象中的DLL文件信息,Action对象通过AssemblyManager类获得Assembly对象。

  ⑥ Action对象使用Assembly对象创建TypeManager对象。

  ⑦ Action对象传递MethodObject对象给TypeManager对象。

  ⑧ TypeManager对象可依据MethodObject对象获得ClassObject对象。并使用ClassObject对象信息动态创建一个外部ClassObject对象的实例instance。

  ⑨ TypeManager对象使用instance和MethodObject对象信息调用instance的动态方法。instance把执行结果返回给Action对象。

  ⑩ Action对象把执行结果返回给外部应用。 

                                             

                                                                图10  PlugPlatform实现的顺序图

其中Plus工厂模式采用了Factory模式。对于Assembly的生成采用了Singleton模式。

4.4 异常处理

   由于应用程序中有很多不可预料的问题,本平台在很多地方都有可能出现人为错误,如找不到配置文件;配置文件的格式不对,不能解析配置文件;类或接口名称写错了,不能实例化类;方法名称写错了,不能执行方法等等。增加异常处理主要是增强其容错性,在这里就不做更多的说明。

5.应用实例

   本例子程序主要有三个方面组成:XML配置文件、外部DLL文件和PlusPlatform调用代码。

  5.1 XML配置文件

   采用的XML配置文件有两个,一个是针对类对象的XML配置文件,一个是针对接口对象的配置文件。

  其中类对象的XML配置文件: 

 

<?xml version="1.0" encoding="utf-8" ?>
<PlugPlatformResource>
  <DllFile name="UserLibrary.dll" filepath ="/" objectType ="class">
    <classobject name="UserLibrary.UserTest1" >
      <Methodobject>testAction01</Methodobject>
      <Methodobject>testAction02</Methodobject>
      <Methodobject>testAction03</Methodobject>
    </classobject>
    <classobject name="UserLibrary.UserTest2" >
      <Methodobject>testAction01</Methodobject>
    </classobject>   
  </DllFile>
</PlugPlatformResource>

接口对象的配置文件与类对象配置文件基本相同,只不过配置信息中由类换成了接口:

<?xml version="1.0" encoding="utf-8" ?>
<PlugPlatformResource>
  <DllFile name="UserLibrary.dll" filepath ="/" objectType ="interface">   
    <interfaceobject name="InterfaceTest1"  implement="UserLibrary.UserTest2" >
      <Methodobject>testAction01</Methodobject>
    </interfaceobject>
  </DllFile>

</PlugPlatformResource> 

5.2 DLL文件内容

   其编译的DLL文件为UserLibrary.dll,该dll文件包括两个类和一个接口,其内部代码为:  

public class UserTest1  
{
   public DynamicArrayObject testAction01(DynamicArrayObject outObject) 
      {
      DynamicArrayObject thisObject = new DynamicArrayObject();
      //分解DynamicArrayObject
      DataValueObject do1 = null;
      string ls = null;
      for (int i = 0; i < outObject.Length; i++) 
            {
        do1 = outObject.getObject(i);
        ls += (String)do1.getDataValue(); 
            }
      DataValueObject do2 = new DataValueObject();
      do2.setDataType(do1.getDataType()).setDataValue(ls);
      //组装DynamicArrayObject,返回DynamicArrayObject
      thisObject.addObject(do2);
      return thisObject;
   }
 
   public DynamicArrayObject testAction02(DynamicArrayObject outObject) 
      {
      return outObject; 
       }
}
 
public class UserTest2 : InterfaceTest1 
{
   public DynamicArrayObject testAction01(DynamicArrayObject outObject) 
      {
     DynamicArrayObject thisObject = new DynamicArrayObject();          
     //分解DynamicArrayObject
     DataValueObject do1 = null;
     string ls = null;
     for (int i = 0; i < outObject.Length; i++) 
          {
       do1 = outObject.getObject(i);
       ls += (String)do1.getDataValue(); 
          }
     DataValueObject do2 = new DataValueObject();
     do2.setDataType(do1.getDataType()).setDataValue(ls);
     //组装DynamicArrayObject,返回DynamicArrayObject
     thisObject.addObject(do2);
     return thisObject;
   }
 
   public DynamicArrayObject testAction02(DynamicArrayObject outObject)
      {
     return outObject;
      }
}
 
public interface InterfaceTest1 
{
  DynamicArrayObject testAction01(DynamicArrayObject outObject);

} 

 5.3 调用插件平台代码

   调用代码也分为两类,一类是针对类对象处理的,代码如下:

DynamicArrayObject thisObject = new DynamicArrayObject();

DataValueObject do1 = new DataValueObject();
DataValueObject do2 = new DataValueObject();
do1.setDataType("string").setDataValue("类测试:第一个对象值.");            
do2.setDataType("string").setDataValue("第二个对象值.");
thisObject.addObject(do1).addObject(do2);
string dllFile = Application.StartupPath + "\DllClassFile.xml";
         
PlugFactory factory = PlusConfig.BuildFactory(dllFile);
IAction action = factory.CreatAction();
DynamicArrayObject outputObject = action.Execute("UserLibrary.UserTest1.testAction01", thisObject);

 另一类是针对接口对象处理,代码如下:

DynamicArrayObject thisObject = new DynamicArrayObject();

DataValueObject do1 = new DataValueObject();
DataValueObject do2 = new DataValueObject();
do1.setDataType("string").setDataValue("接口测试:第一个对象值.");           
do2.setDataType("string").setDataValue("第二个对象值.");
thisObject.addObject(do1).addObject(do2);
string dllFile = Application.StartupPath+"\DllInterfaceFile.xml";
 
PlugFactory factory = PlusConfig.BuildFactory(dllFile);
IAction action = factory.CreatAction();
DynamicArrayObject outputObject = action.Execute("InterfaceTest1.testAction01", thisObject);

 

可以对返回的DynamicArrayObject做分解查看,满足设计要求。

6.结束语

   反射机制结合动态数组很好地解决了应用软件的后期维护和升级。对于应用软件的变化,可不改动任何现有的程序,只要修改XML配置文件的相应对象名称和加载新的对象即可,程序不需要任何的重编、重启和硬性改动,并保证了原应用系统的可复用性从而实现降低耦合度,实现复用的目标。

  本模型在层与层之间借助类调用和接口实现,利用反射机制把调用者与实现者在编译期分离。运行期通过读配置文件动态加载实现类,并通过接口将实现者强制转型,使其为调用者所用,完成调用者和实现者的解耦。但是,这个功能并不是完全完善,对于插件平台也有很多的改进性,如果能对类和接口配置文件更加丰富,把插件平台升级为一个框架容器,该容器能把对象之间的依赖关系先行剥离,然后在适当时候由容器负责产生具体的实例再注射到调用者中,即控制权由应用代码中转到了外部容器,控制权发生了转移。即所谓的控制反转模式,这种模式在java中已经有比较成熟的框架,如Spring等。相信凭借Microsoft.Net庞大的技术框架平台,在C#上也会有这样的控制反转框架出现。 

 

posted on 2011-10-21 23:54  JCreator  阅读(559)  评论(0)    收藏  举报