Service Config 动态加载 :: 风之谷

来源: BlogBus 原始链接: http://jnn.blogbus.com:80/logs/2004/05/182055.html 存档链接: https://web.archive.org/web/20060224191700id_/http://jnn.blogbus.com:80/logs/2004/05/182055.html


风之谷 有关ACE/TAO,还有CORBA的学习资料 <<<ACE同步策略实现(-) | 首页 | API 学习之我见>>> Service Config 动态加载 时间:2004-05-19 在开发和维护的过程中,很多时候会涉及一个问题,就是如何实现派生类的动态加载。 由于C++本身不支持动态类的加载机制,需要通过其他的方式来进行支持。因此在ACE 中专门设计了service config框架来解决这样的问题。 service config框架,通过修改配置文件,能够实现对派生于ACE_Service_Object的服务 对象的加载,在service config中根据加载服务代码方式的不同可以分为: 静态服务 是被静态链接至应用程序的服务 动态服务 是从一个和多个共享库中链接的服务 由于本文讨论的重点时动态类的加载机制,因此主要讨论service config中有关动态 服务的实现,其他的实现内容,大家可以参考 C++NPV2中的第5章。 在这里主要是从原理方面,简单分析service config框架的实现。 在分析service config框架之前,需要明确service config需要实现的功能: 1.我们写的新的服务需要在运行时(不是在编译时)能够被service config框架识别以及调用。 2.其次是服务对象的生命周期由service config框架进行管理。 3.通过配置文件,来获知服务对象加载信息。 对于前面提到的两点功能,只需要我们写的服务类继承ACE_Service_Object ,实现 这个类所提供的init(),fini(),suspend(),resume(),info()对服务管理的方法。由于 ACE_Service_Object继承了ACE_Event_Handler,因此可以实现相关服务处理的方法。 对与第三点来说,如果是用Java语言来实现service config框架,那也很容易, 可以通过动态类型识别(RTTI),在语言运行库中,就提过了描述Class信息的机制, 使用著名的Class.forName(),可以获得需要加载类的主要信息。 而对于C++来说,这就比较麻烦了,主要是需要解决有关类信息描述的问题。对于DLL来说, 如果直接将对象进行输出的话,由于C++所支持的重载机制,输出的类方法名会结合参数产生变化, 如果想通过service config框架,加载DLL输出的类,就必须通过静态编译的方法,获知类的定义。 而我们的要求是在程序运行时来,通过配置文件中定义的dll名,以及相关的类名来加载相关的服务类。 通过分析源码,我们可以发现一些有意思的东东。

define ACE_Local_Service_Export

define ACE_FACTORY_DEFINE(CLS,SERVICE_CLASS) \

void gobble##SERVICE_CLASS (void *p) {
ACE_Service_Object *_p = ACE_static_cast (ACE_Service_Object *, p);
ACE_ASSERT (_p != 0);
delete _p; }
extern "C" CLS##_Export ACE_Service_Object *
make##SERVICE_CLASS (ACE_Service_Object_Exterminator gobbler)
{
ACE_TRACE (#SERVICE_CLASS);
if (gobbler != 0)
gobbler = (ACE_Service_Object_Exterminator) gobble##SERVICE_CLASS;
return new SERVICE_CLASS;
} /// The canonical name for a service factory method #define ACE_SVC_NAME(SERVICE_CLASS) make##SERVICE_CLASS /// The canonical way to invoke (i.e. construct) a service factory /// method. #define ACE_SVC_INVOKE(SERVICE_CLASS) make##SERVICE_CLASS (0) //@} /
@name Helper macros for services defined in the netsvcs library. *

  • The ACE services defined in netsvcs use this helper macros for
  • simplicity.

*/ //@{

define ACE_SVC_FACTORY_DECLARE(X) ACE_FACTORY_DECLARE (ACE_Svc, X)

define ACE_SVC_FACTORY_DEFINE(X) ACE_FACTORY_DEFINE (ACE_Svc, X)

//@} ACE_SVC_FACTORY_DECLARE (...) 在这里用...来代替具体的类名 make... (ACE_Service_Object_Exterminator *gobbler) 是dll输出的调用接口 (注意是C方式进行输出的,如果是C++的话就另当别论了),我们需要在svc.conf中写出输出的 调用函数名。 make... 这个宏精妙之处就在于此,由于C++不支持reflect机制,为了能够让Service_Config类 在不做任何改变的情况下,就能创建相关的ACE_Service_Object 继承类的实例,make提供了一个 创建类实例的方法。 这也许是Factory模式的另类应用,其实这个方法在某些环境很有效, 也可以帮助我们将C++的类对象输出至delphi中,供delphi进行调用。 return new SERVICE_CLASS; 这样就有人会问了,提供new,如何提供delete呢? 大家再看一下_gobble...这个宏定义, 从 ACE_Service_Object_Exterminator *gobbler 的定义 typedef void (*ACE_Service_Object_Exterminator)(void *); 可知 ACE_Service_Object_Exterminator 是一个函数指针 而gobbler定义是指向这个函数指针的指针。 通过给gobbler赋值,就可以给service config框架提供释放的ACE_Service_Object派生类的方法了。 还有为什么在_gobble...函数中需要 ACE_Service_Object *p = ACE_static_cast (ACE_Service_Object *, p); 来一个强制转换呢? 强制转换是因为 gobble##SERVICE_CLASS (void *p) 中的p是无类型指针,强制转换成ACE_Service_Object * 类型, delete *p 时,就可以调用p所指向的ACE_Service_Object子类的析构函数。 svc.conf 示例文件 dynamic Timer_Service_3 Service_Object * ./Timer:make_Timer_Service_3() "timer $INTERVAL $MAX_TIMEOUTS $TRACE" 里面没有有关_gobble##SERVICE_CLASS 函数的描述, 这是因为_make##SERVICE_CLASS 的宏定义中已经完成有关析构函数的注册工作了。 jnn 发表于 2004-05-19 08:40 引用Trackback(0) | 编辑 评论 对于动态配置的过程,你写的蛮详细的,但是我一直在琢磨:如果多个服务需要交互,那么一个服务停止之前,如何通知其他服务?使得在其他服务做出响应之后,本服务才真正被remove。这一套连锁反应,不知道你有没有琢磨过?希望能够交流心得 lanzhu ( ) 发表于 2004-06-01 14:46 发表评论 最后更新