动态加载Java运行环境和运行实例
最近想做一个Java软件,可以动态的增加插件。插件的数据、资源和软件全部在插件内部。增加插件时,不需要对原有的软件进行新的配置和修改。实现方法并不复杂,插件的一个配置文件中配置了,这个插件的定义、参数和软件的调入口。然后软件运行时,对插件文件夹进行扫描,如果发现新插件,那么就将这个插件加载到软件中。通过动态加载类的方式可以调用这个插件。
但是存在一个问题是,如何将这些java资源加载到java运行环境中?
后来在网上发现有两种方法,一种是通过反射机制对系统运行的ClassLoader进行操作,向其中添加运行环境。因为这个方法是protected,无法调用,所以只能通过反射机制来处理。另一种方法是通过改写ClassLoader,来加载自己的环境,然后在运行java时,通过参数-Djava.system.class.loader=XXXX来使用自己的类加载器。
下面是两个例子:
1
/*
2
* HelloWorld.java
3
* 编译完之后,将其class文件放到C盘下
4
*/
5
public class HelloWorld {
6
7
public void print(String s) {
8
System.out.println("HelloWorld");
9
}
10
}
11
12

2

3

4

5

6

7

8

9

10

11

12

1
/*
2
* PackageManager.java
3
* 动态向系统类加载器中添加新环境
4
*/
5
import java.io.File;
6
import java.lang.reflect.Method;
7
import java.net.URL;
8
import java.net.URLClassLoader;
9
import java.util.StringTokenizer;
10
11
public class PackageManager {
12
public static final String CLASS_PATH = "classpath";
13
static URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
14
static Class sysclass = URLClassLoader.class;
15
static Method method;
16
17
public static void importClasspath() {
18
try {
19
StringTokenizer st = new StringTokenizer(System.getenv(CLASS_PATH), ";");
20
while(st.hasMoreTokens())
21
addURL(st.nextToken());
22
} catch(Exception ex) { ex.printStackTrace(); }
23
}
24
25
public static void addURL(String path) {
26
try {
27
addURL((new File(path)).toURL());
28
} catch(Exception ex) { ex.printStackTrace(); }
29
}
30
31
public static void addURL(URL u) {
32
try {
33
if(method == null) {
34
Class[] cs = new Class[] {URL.class};
35
method = sysclass.getDeclaredMethod("addURL", cs);
36
method.setAccessible(true);
37
}
38
method.invoke(sysloader,new Object[]{ u });
39
} catch (Exception ex) {
40
ex.printStackTrace();
41
//throw new IOException("Error, could not add URL to system classloader");
42
}
43
}
44
45
/**
46
* 动态加载环境和动态加载类方法
47
*/
48
public static void main(String[] args) {
49
// importClasspath();
50
addURL("C:\\");
51
try {
52
Class c = sysloader.loadClass("HelloWorld");
53
Method main = c.getDeclaredMethod("print",
54
new Class[] { String.class });
55
56
if (main == null) {
57
System.out.println("main is null");
58
} else {
59
main.invoke(c.newInstance(), new Object[] { "s" });
60
}
61
62
} catch (Exception e) {
63
e.printStackTrace();
64
}
65
}
66
}
67
68

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

1
/**
2
* ConfigurableClassLoader
3
* 改写ClassLoader类
4
* 这个好处在于,可以将所有的运行时问题,全部在程序中动态加载
5
* 从而,不需要编写复杂的Java运行环境批处理文件
6
*/
7
8
import java.io.File;
9
import java.lang.reflect.InvocationTargetException;
10
import java.lang.reflect.Method;
11
import java.net.MalformedURLException;
12
import java.net.URL;
13
import java.net.URLClassLoader;
14
15
public class ConfigurableClassLoader extends URLClassLoader {
16
public ConfigurableClassLoader(ClassLoader parent)
17
{
18
super(new URL[0], parent);
19
20
String property = System.getProperty("user.class.pool");
21
22
if (property != null) {
23
String[] paths = property.split(File.pathSeparator);
24
for (int i = 0; i < paths.length; ++i) {
25
try {
26
if (paths[i].startsWith("http:") || paths[i].startsWith("file:"))
27
addURL(new URL(paths[i]));
28
else
29
addURL(new File(paths[i]).toURL());
30
}
31
catch (MalformedURLException e) {
32
e.printStackTrace();
33
}
34
}
35
}
36
}
37
38
protected void addURL(URL url)
39
{
40
super.addURL(url);
41
}
42
43
public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
44
{
45
Class mainClass = Class.forName(args[0], false, ClassLoader.getSystemClassLoader());
46
Method entryMethod = mainClass.getMethod("main", new Class[] {String[].class});
47
String[] appArgs = new String[args.length - 1];
48
System.arraycopy(args, 1, appArgs, 0, appArgs.length);
49
entryMethod.invoke(null, new Object[] {appArgs});
50
}
51
}
52
53

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

1
/**
2
* 这是对改写ClassLoader的测试方法
3
*/
4
import java.lang.reflect.Method;
5
import java.net.URLClassLoader;
6
7
public class TestMyClassLoader {
8
9
public static void main(String[] args) {
10
try {
11
URLClassLoader sysloader = (URLClassLoader) ClassLoader
12
.getSystemClassLoader();
13
Class c = sysloader.loadClass("HelloWorld");
14
Method main = c.getDeclaredMethod("print",
15
new Class[] { String.class });
16
17
if (main == null) {
18
System.out.println("main is null");
19
} else {
20
main.invoke(c.newInstance(), new Object[] { "s" });
21
}
22
23
} catch (Exception e) {
24
e.printStackTrace();
25
}
26
}
27
}
28
29

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

测试时运行这个命令
java -Duser.class.pool=c:\ -Djava.system.class.loader=ConfigurableClassLoader TestMyClassLoader