Java的ClassLoader與Package機制介紹了ClassLoader的委派機制,它是把裝載的任務傳遞給上級的裝載器的,依次類推,直到啟動類裝載器(沒有上級類裝載器)。如果啟動類裝載器能夠裝載這個類,那么它會首先裝載。如果不能,則往下傳遞。其實這引出一個運行時包的概念。不同裝載器裝載的類,即使包名相同也不能互相訪問。這樣保證了核心類庫不被破壞。(by juxtapose)
本文將講述如何擴展ClassLoader類實現一個自己的類裝載器,每個Class對象都有一個引用指向裝載他的ClassLoader,你可以通過public ClassLoader getClassLoader()方法得到它。為了創建自己的類裝載器我們應該擴展ClassLoader類,這是一個抽象類。我們目的是從本地文件系統使用我們實現的類裝載器裝載一個類。我們創建一個FileClassLoader extends ClassLoader。我們需要覆蓋ClassLoader中的
findClass(String name)方法,這個方法通過類的名字而得到一個Class對象。
1
public Class findClass(String name)
2

{
3
byte[] data = loadClassData(name);
4
return defineClass(name, data, 0, data.length);
5
}
6
我們還應該提供一個方法loadClassData(String name),通過類的名稱返回class文件的字節數組。然后使用ClassLoader提供的defineClass()方法我們就可以返回Class對象了。
1
public byte[] loadClassData(String name)
2

{
3
FileInputStream fis = null;
4
byte[] data = null;
5
try
6

{
7
fis = new FileInputStream(new File(drive + name + fileType));
8
ByteArrayOutputStream baos = new ByteArrayOutputStream();
9
int ch = 0;
10
while ((ch = fis.read()) != -1)
11

{
12
baos.write(ch);
13
14
}
15
data = baos.toByteArray();
16
} catch (IOException e)
17

{
18
e.printStackTrace();
19
}
20
21
return data;
22
}
23
這里我們是從D盤裝載一個類。
下面我們提供一個類public class MyApp{},類中沒有定義任何方法和變量,下面我們編譯MyApp.java得到MyApp.class,然后把文件放在D盤的根目錄。為了證明MyApp.class是被我們定義的classloader裝載的,我們在FileClassLoader的main()方法中打印出裝載MyApp.class的類裝載器的名稱。
1
public static void main(String[] args) throws Exception
2

{
3
FileClassLoader loader = new FileClassLoader();
4
Class objClass = loader.loadClass("MyApp", true);
5
Object obj = objClass.newInstance();
6
System.out.println(objClass.getName());
7
System.out.println(objClass.getClassLoader());
8
9
10
}
11
編譯FileClassLoader
javac FileClassLoader.java 然后運行java FileClassLoader 可以看到輸出結果為
MyApp
FileClassLoader@1a5ab41
如果你把MyApp.class放入到你程序的所在目錄會出現什么情況呢?讀者自己實踐一下吧!
結果為:MyApp
sun.misc.Launcher$AppClassLoader@92e78c
下面給出FileClassLoader的源代碼。/*
1
* Created on 2005-7-27
2
3
*
4
5
* To change the template for this generated file go to
6
7
* Window>Preferences>Java>Code Generation>Code and Comments
8
9
*/
10
11
12
/** *//**
13
14
* @author liuxiang
15
16
*
17
18
* To change the template for this generated type comment go to
19
20
* Window>Preferences>Java>Code Generation>Code and Comments
21
22
*/
23
24
import java.io.ByteArrayOutputStream;
25
26
import java.io.File;
27
28
import java.io.FileInputStream;
29
30
import java.io.IOException;
31
32
public class FileClassLoader extends ClassLoader
33
34

{
35
36
public static final String drive = "d:/";
37
38
public static final String fileType = ".class";
39
40
41
public FileClassLoader()
{
42
43
super();
44
45
46
}
47
48
49
public FileClassLoader(ClassLoader arg0)
{
50
51
super(arg0);
52
53
}
54
55
56
public Class findClass(String name)
57
58

{
59
60
byte[] data = loadClassData(name);
61
62
/**//*
63
64
* Converts an array of bytes into an instance of class Class.
65
66
* Before the Class can be used it must be resolved.
67
68
*
69
70
* This method assigns a default ProtectionDomain to the newly
71
72
* defined class. The ProtectionDomain contains the set of
73
74
* permissions granted when a call to Policy.getPolicy().getPermissions()
75
76
* is made with a code source of null,null. The default domain
77
78
* is created on the first invocation of defineClass, and re-used
79
80
* on subsequent calls.
81
82
* To assign a specific ProtectionDomain to the class, use the
83
84
* defineClass method that takes a ProtectionDomain as one of
85
86
* its arguments.
87
88
*/
89
90
/**//*
91
92
* 該方法接受由原始字節組成的數組并把它轉化成class對象
93
94
* 原始字節包含從文件系統或網絡裝入的data
95
96
* defineClass管理JVM中許多復雜、神秘和依賴于實現的方面————
97
98
* ————它把字節碼分析成運行時數據結構、校驗有效性等。
99
100
*/
101
102
return defineClass(name, data, 0, data.length);
103
104
}
105
106
107
/**//*
108
109
* 將對應的Class文件讀為byte[]
110
111
*/
112
113
public byte[] loadClassData(String name)
114
115

{
116
117
FileInputStream fis = null;
118
119
byte[] data = null;
120
121
try
122
123

{
124
125
//裝載d:根目錄下面的.class文件到data中
126
127
fis = new FileInputStream(new File(drive + name + fileType));
128
129
ByteArrayOutputStream baos = new ByteArrayOutputStream();
130
131
int ch = 0;
132
133
while ((ch = fis.read()) != -1)
134
135

{
136
137
baos.write(ch);
138
139
140
}
141
142
data = baos.toByteArray();
143
144
} catch (IOException e)
145
146

{
147
148
e.printStackTrace();
149
150
}
151
152
153
return data;
154
155
}
156
157
158
public static void main(String[] args) throws Exception
159
160

{
161
162
FileClassLoader loader = new FileClassLoader();
163
164
//裝載類MyApp
165
166
Class objClass = loader.loadClass("MyApp", true);
167
168
//生成MyApp的一個實例
169
170
Object obj = objClass.newInstance();
171
172
//獲得類的名稱
173
174
System.out.println(objClass.getName());
175
176
//獲得類的裝載器的名稱
177
178
System.out.println(objClass.getClassLoader());
179
180
}
181
182
}
183
posted on 2007-06-26 14:27
冰封的愛 閱讀(258)
評論(0) 編輯 收藏 所屬分類:
技術