使用C++对java的classloader进行模拟
来源:互联网 发布:淘宝海报制作软件 编辑:程序博客网 时间:2024/05/16 23:40
转自:使用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就可能会出问题,更好地办法是传递一个表示参数个数的值。
- 使用C++对java的classloader进行模拟
- java中模拟c中对sizeof的实现
- 使用swig进行C/C++对Python的扩展
- 类加载器(ClassLoader)对java安全性的支持
- PHP使用CURL对带有验证码的网站进行模拟登录
- Java中使用SSHA对数据进行加密的示例
- java 对各个盘符的使用情况进行查看
- 使用java提供的api对文件进行压缩解密
- 使用Java对两个对象的属性进行拷贝
- Java使用jxl对excel文件进行简单的读写
- 使用java对图像进行切分的程序及注意事项
- Java 使用Map对出现的字符进行计数
- 使用Java的对UTF8URL进行编码方式
- C#:使用MD5对密码进行加密!
- 使用VS(C#) 对Mysql 进行操作
- 对自定义对象进行排序(C++/Java)
- 关于ClassLoader的使用
- Java的Classloader
- 【网摘】使用结构体作为返回值
- null
- oracle跳跃索引的应用场合
- 正则表达式
- MyEclipse的优化与个性化
- 使用C++对java的classloader进行模拟
- Oracle索引使用规则
- 李嘉诚财富秘密:钱来的很容易
- TextBox控件的多样边框实现
- 各大企业将如何实现真正意义上的融合?
- 谷歌不会退出中国,纯粹炒作!
- JAVA乱码问题汇总
- 国产自动化测试工具
- 看淡智能本/上网本,平板电脑有潜力