使用C++对java的classloader进行模拟

转自:使用C++对java的classloader进行模拟

 

一直以来,觉得java的classloader很不错的,做产品的话,可以将基本的做下来后,将扩展通过classloader的方式来做,将更新的补 丁使用classloader来做,在使用java的网络游戏中,可以将扩展通过classloader的机制,实现动态的更新,省的每次更新要重新下载 客户端,在手机上可是一个很不错的点子。
erlang也支持代码的热部署,java也可以动态更新,那么,C++呢,思来考去,没有想到类似非常完美的方案,只能知道一个基本成型的内容。

现在,不管是windows还是linux,都支持dll,我们可以动态的加载dll,是否可以像java那样,动态的调用函数呢?答案是可以的。需要借 助部分汇编来实现,要知道,我们可能只是知道一个函数的名字,函数参数的类型,参数的个数等等,都是不知道的。因为我更想做一个普遍使用的,而不是要告诉 你:“把某某的头文件给我”。
首先看外表的内容,java的ClassLoader的模拟接口:
ClassLoader.h

01         #ifndef _CLASSLOADER_H_
02 #define _CLASSLOADER_H_
03 #include "define.h"
04 #include "String.h"
05 class ClassLoader
06 {
07 public :
08          ClassLoader();
09          ClassLoader(ClassLoader* parent);
10          virtual ~ClassLoader();
11          void load( const String& name);
12          void * getFun( const String& name);
13 private :
14          ClassLoader* parent;
15          void * dl_handle;
16 };
17 #endif /* _CLASSLOADER_H_ */

接下来是ClassLoader.cpp

01         #include "java/lang/ClassLoader.h"
02 #include < dlfcn.h >
03 #include "System.h"
04 ClassLoader::ClassLoader()
05 {
06          dl_handle = 0;
07 }
08  
09 ClassLoader::~ClassLoader()
10 {
11          if (dl_handle) {
12                  dlclose(dl_handle);
13          }
14          dl_handle = 0;
15 }
16  
17 ClassLoader::ClassLoader(ClassLoader* parent)
18 {
19          dl_handle = 0;
20          this ->parent = parent;
21 }
22 void ClassLoader::load( const String& name)
23 {
24          System::out:: printf ( "ClassLoader::load %s/n" , ( char *)name);
25          dl_handle = dlopen(( char *)name, RTLD_LAZY);
26          if (!dl_handle) {
27                   System::out:: printf ( "!!! %s/n" , dlerror());
28          }
29 }
30  
31 void * ClassLoader::getFun( const String& name)
32 {
33          System::out:: printf ( "ClassLoader::getFun %s/n" , name.c_str());
34          void * fun = dlsym(dl_handle, name.c_str());
35          char * error = dlerror();
36          if (error != 0) {
37                  System::out:: printf ( "error %s/n" , error);
38                  return 0;
39          } else
40                  return fun;
41 }

java的Class的封装:
Class.h

01         #ifndef _CLASS_H_
02 #define _CLASS_H_
03 #include "define.h"
04 #include "String.h"
05 class Object;
06 class Method;
07 class ClassLoader;
08 class Class
09 {
10 public :
11          Class();
12          Class( const Class& aClass);
13          virtual ~Class();
14          Object* newInstance();
15          static Class forName( const String& name, boolean initialize,   /
16                                ClassLoader* loader);
17          Method* getMethod( const String& name, void * parm);
18          ClassLoader* loader;
19          String name;
20          boolean initialize;
21 };
22 #endif /* _CLASS_H_ */

java的Class的封装实现:
Class.cpp

01         #include "java/lang/Class.h"
02 #include "java/lang/Object.h"
03 #include "java/lang/reflect/Method.h"
04 #include "java/lang/ClassLoader.h"
05 #include "System.h"
06 #include < dlfcn.h >
07 Class::Class()
08 {
09          loader = 0;
10          initialize = false ;
11 }
12  
13 Class::Class( const Class& aClass)
14 {
15          this ->name = aClass.name;
16          this ->loader = aClass.loader;
17          this ->initialize = aClass.initialize;
18 }
19 Class::~Class()
20 {
21  
22 }
23  
24 Class Class::forName( const String& name, boolean initialize,   /
25                        ClassLoader* loader)
26 {
27          Class ret;
28          ret.name = name;
29          ret.initialize = initialize;
30          ret.loader = loader;
31          if (ret.loader != 0) {
32                  ret.loader->load(name);
33          }
34          return ret;
35 }
36  
37 Object* Class::newInstance()
38 {
39          System::out::println( this ->name);
40          Object* ret = new Object();
41          ret->c.name = this ->name;
42          ret->c.initialize = this ->initialize;
43          ret->c.loader = this ->loader;
44          return ret;
45 }
46  
47 Method* Class::getMethod( const String& name, void * parm)
48 {
49          System::out::println( "Class::getMethod" );
50          System::out::println( this ->name);
51          System::out::println(name);
52          return new Method( this ->loader->getFun(name));
53 }

Java的函数Method 的封装:
Method.h

01         #ifndef _METHOD_H_
02 #define _METHOD_H_
03  
04 #include "String.h"
05 class Object;
06 class Method
07 {
08 public :
09          Method();
10          virtual ~Method();
11          Method( void * fun);
12          void invoke(Object* obj, ... );
13          void * fun;
14 };
15  
16 #endif /* _METHOD_H_ */

上面的内容,没什么好说的,linux下编译,理论上,windows也是可以的,只是调用的函数不一样而已。核心的实现在Method的实现中,毕竟,我们做了这么多,就是为了调用函数。这是实现:
Method.cpp

01         #include "java/lang/reflect/Method.h"
02 #include "java/lang/Object.h"
03 #include "stdarg.h"
04 Method::Method()
05 {
06          this ->fun = 0;
07 }
08  
09 Method::~Method()
10 {
11  
12 }
13  
14 void Method::invoke(Object* obj, ...)
15 {
16          if ( this ->fun == 0)
17                  return ;
18          typedef void (*func)( void * ...);
19          func fun;
20          va_list ap;
21          int inc = 0;
22          va_start (ap, obj);
23          void ** arg = 0;
24          while ( true ) {
25                  void * s = va_arg (ap, void *);
26                  if (s == 0)
27                          break ;
28                  inc+=4;
29          }
30          int argc = inc/4;
31          arg = new void *[argc];
32          va_start (ap, obj);
33          while ( true ) {
34                  void * s = va_arg (ap, void *);
35                  if (s == 0)
36                          break ;
37                  argc--;
38                  arg[argc] = s;
39          }
40          va_start (ap, obj);
41          while ( true ) {
42                  void * s = va_arg (ap, void *);
43                  if (s == 0) {
44                          asm( "call %0/n" : : "m" ( this ->fun));
45                          asm( "add %0, %%esp/n" : : "m" (inc));
46                          break ;
47                  } else {
48                          asm( "push %0/n" : : "m" (arg[argc]));
49                  }
50                  argc++;
51          }
52          delete [] arg;
53          va_end (ap);
54 }
55  
56 Method::Method( void * fun)
57 {
58          this ->fun = fun;
59 }

核心的内容总是占用了很大的代码实现,理论上来说,使用汇编会更少一些,大部分的代码都是在对参数进行处理,由于C/C++没有对不定参数参数长度的处理(我没有找到,如果有谁记得找到通知我一声)。这里使用了判断参数是否为0来决定参数是否结束。
首先第一步统计参数的个数,每个参数限定为指针。
第二步复制参数,按照倒着的顺序复制参数,这样使得接下来的调用函数的参数顺序正确。
第三步就是汇编的调用:

va_start(ap, obj);
while (true) {
void* s = va_arg(ap, void*);
if (s == 0) {
asm("call %0/n" : :"m"(this->fun));
asm("add %0, %%esp/n": :"m"(inc));
break;
}else {
asm("push %0/n" : :"m"(arg[argc]));
}
argc++;
}

将参数按照模拟数序push到堆栈中,然后,再模拟函数调用,最后平衡堆栈。
下面是一个使用的例子:

ClassLoader* loader = new ClassLoader();

// create a new instance of this class using new classloader
Object* boot = Class::forName("liblauncher.so", false, loader).newInstance();

Method* m1 = boot->getClass().getMethod("launch", (Class*) null);
m1->invoke(boot, NULL);
delete m1;
delete loader;

注意:
上述的方法其实还是有一定的限制的,要求参数必须是指针或者整型,对于传递引用可能会引起问题,另外一个就是我因为使用的0来判断结束,所以如果参数传递了0就可能会出问题,更好地办法是传递一个表示参数个数的值。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值