类加载器测试
1.测试加载文件路径
public
class
ClassloaderTest {
public
static
void
main(String[] args) {
//启动类加载器加载类的文件
System.
out
.println(System.getProperty(
"sun.boot.class.path"
));
//扩展类加载器加载类的文件
System.
out
.println(System.getProperty(
"java.ext.dirs"
));
//系统类加载器加载类的文件
System.
out
.println(System.getProperty(
"java.class.path"
));
}
}
结果显示:
C:\Program Files\Java\jdk1.7.0_17\jre\lib\resources.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\rt.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\sunrsasign.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\jce.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.7.0_17\jre\classes
C:\Program Files\Java\jdk1.7.0_17\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
E:\eclipsenew\workspace\RedisTest\bin;C:\Users\***\.m2\repository\
redis\clients\jedis\2.6.0\jedis-2.6.0.jar
2.测试classloader体系结构
public
class
ClassloaderTest {
public
static
void
main(String[] args)
throws
Exception {
System.
out
.println(Thread.currentThread().getContextClassLoader());
System.
out
.println(ClassloaderTest.
class
.getClassLoader());
System.
out
.println(System.
class
.getClassLoader());
System.
out
.println(ClassLoader.getSystemClassLoader());
System.
out
.println(ClassLoader.getSystemClassLoader().getParent());
System.
out
.println(ClassLoader.getSystemClassLoader().getParent().getParent());
}
}
结果显示:
sun.misc.Launcher$AppClassLoader@533e846f
sun.misc.Launcher$AppClassLoader@533e846f
null
sun.misc.Launcher$AppClassLoader@533e846f
sun.misc.Launcher$ExtClassLoader@2d68be1b
null
System.java这样的由系统提供的类都在rt.jar中,由Bootstrap ClassLoader加载,由于Bootstrap类加载器不是Java写的,所以打印出来的类名为null
3.测试类的类加载器
package
sms;
public
class
ClassloaderTest {
public
static
void
main(String[] args)
throws
Exception {
ClassLoader cl = ClassLoader.getSystemClassLoader();
System.
out
.println(cl);
while
(cl !=
null
) {
cl = cl.getParent();
System.
out
.println(cl);
}
try
{
Class c = Class.forName(
"java.lang.Object"
);
cl = c.getClassLoader();
System.
out
.println(
"java.lang.Object's loader is "
+ cl);
c = Class.forName(
"sms.ClassloaderTest"
);
cl = c.getClassLoader();
System.
out
.println(
"ClassloaderTest's loader is "
+ cl);
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
结果显示:
sun.misc.Launcher$AppClassLoader@533e846f
sun.misc.Launcher$ExtClassLoader@2d68be1b
null
java.lang.Object's loader is null
ClassloaderTest's loader is sun.misc.Launcher$AppClassLoader@533e846f
第一行表示,系统类装载器实例化自类sun.misc.Launcher$AppClassLoader
第二行表示,系统类装载器的parent实例化自类sun.misc.Launcher$ExtClassLoader
第三行表示,系统类装载器parent的parent为bootstrap
第四行表示,核心类java.lang.Object是由bootstrap装载的
第五行表示,用户类LoaderSample1是由系统类装载器装载的
4.自定义classloader (一)
public
class
ClassLoaderTest1
extends
ClassLoader {
private
ClassLoader
parent
=
null
;
private
String
path
;
public
ClassLoaderTest1(String path) {
this
.
path
= path;
}
public
ClassLoaderTest1(ClassLoader parent, String path) {
super
(parent);
this
.
parent
= parent;
this
.
path
= path;
}
@Override
public
Class<?> loadClass(String name)
throws
ClassNotFoundException {
System.
out
.println(
"name:"
+ name);
Class<?> cls = findLoadedClass(name);
if
(cls ==
null
) {
ClassLoader parent2 = getParent().getParent();
try
{
//System.out.println("parent2 : " + parent2);
System.
out
.println(
"try to use ExtClassLoader to load class : "
+ name);
cls = parent2.loadClass(name);
System.
out
.println(
"real cls : "
+ cls);
System.
out
.println(
"real ClassLoader : "
+ cls.getClassLoader());
}
catch
(ClassNotFoundException e) {
System.
out
.println(
"ExtClassLoader.loadClass :"
+ name +
" Failed"
);
}
if
(cls ==
null
) {
System.
out
.println(
"try to ClassLoaderTest1 load class : "
+ name);
cls = findClass(name);
if
(cls ==
null
) {
System.
out
.println(
"ClassLoaderTest1.loadClass :"
+ name +
" Failed"
);
}
else
{
System.
out
.println(
"ClassLoaderTest1.loadClass :"
+ name +
" Successful"
);
System.
out
.println(
"real ClassLoader : "
+ cls.getClassLoader());
}
}
else
{
System.
out
.println(
"ExtClassLoader.loadClass :"
+ name +
" Successful"
);
System.
out
.println(
"real ClassLoader : "
+ cls.getClassLoader());
}
}
return
cls;
}
@Override
protected
Class<?> findClass(String name)
throws
ClassNotFoundException {
System.
out
.println(
"try findClass "
+ name);
InputStream is =
null
;
Class class1 =
null
;
try
{
String classPath = name.replace(
"."
,
"\\"
) +
".class"
;
String classFile =
path
+ classPath;
System.
out
.println(
"classFile:"
+classFile);
byte
[] data = getClassFileBytes(classFile);
System.
out
.println(
"class1 begin :"
+class1);
class1 = defineClass(name, data, 0, data.
length
);
System.
out
.println(
"class1 end :"
+class1);
if
(class1 ==
null
) {
System.
out
.println(
"ClassLoaderLK.findClass() ERR "
);
throw
new
ClassFormatError();
}
}
catch
(FileNotFoundException e) {
e.printStackTrace();
}
catch
(IOException e) {
e.printStackTrace();
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
if
(is !=
null
) {
try
{
is.close();
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
return
class1;
}
private
byte
[] getClassFileBytes(String classFile)
throws
Exception {
FileInputStream fis =
new
FileInputStream(classFile);
FileChannel fileC = fis.getChannel();
ByteArrayOutputStream baos =
new
ByteArrayOutputStream();
WritableByteChannel outC = Channels.newChannel(baos);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while
(
true
) {
int
i = fileC.read(buffer);
if
(i == 0 || i == -1) {
break
;
}
buffer.flip();
outC.write(buffer);
buffer.clear();
}
fis.close();
return
baos.toByteArray();
}
public
static
void
main(String[] args) {
String ext =
"java.ext.dirs"
;
System.
out
.println(
"java.ext.dirs :\n"
+ System.getProperty(ext));
String cp =
"java.class.path"
;
System.
out
.println(
"java.class.path :\n"
+ System.getProperty(cp));
ClassLoader currentClassloader = ClassLoaderTest1.
class
.getClassLoader();
System.
out
.println(
"currentClassloader is "
+ currentClassloader);
String pp =
"E:\\eclipsenew\\workspace\\RedisTest\\bin\\"
;
ClassLoaderTest1 cl =
new
ClassLoaderTest1(currentClassloader, pp);
System.
out
.println();
System.
out
.println();
String name =
"sms.DataBean"
;
try
{
Class<?> loadClass = cl.loadClass(name);
Object object = loadClass.newInstance();
System.
out
.println();
System.
out
.println(
" invoke some method !"
);
System.
out
.println();
Method method = loadClass.getMethod(
"showData"
);
method.invoke(object);
}
catch
(Exception e) {
}
}
}
显示结果:
java.ext.dirs :
C:\Program Files\Java\jdk1.7.0_17\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
java.class.path :
E:\eclipsenew\workspace\RedisTest\bin;。。。。。。
name:sms.DataBean
try to use ExtClassLoader to load class : sms.DataBean
ExtClassLoader.loadClass :sms.DataBean Failed
try to ClassLoaderTest1 load class : sms.DataBean
try findClass sms.DataBean
classFile:E:\eclipsenew\workspace\RedisTest\bin\sms\DataBean.class
class1 begin :null
name:sms.BaseBean
try to use ExtClassLoader to load class : sms.BaseBean
ExtClassLoader.loadClass :sms.BaseBean Failed
try to ClassLoaderTest1 load class : sms.BaseBean
try findClass sms.BaseBean
classFile:E:\eclipsenew\workspace\RedisTest\bin\sms\BaseBean.class
class1 begin :null
name:java.lang.Object
try to use ExtClassLoader to load class : java.lang.Object
real cls : class java.lang.Object
real ClassLoader : null
ExtClassLoader.loadClass :java.lang.Object Successful
real ClassLoader : null
class1 end :class sms.BaseBean
ClassLoaderTest1.loadClass :sms.BaseBean Successful
real ClassLoader : sms.ClassLoaderTest1@334021a9
class1 end :class sms.DataBean
ClassLoaderTest1.loadClass :sms.DataBean Successful
real ClassLoader : sms.ClassLoaderTest1@334021a9
invoke some method !
name:java.lang.String
try to use ExtClassLoader to load class : java.lang.String
real cls : class java.lang.String
real ClassLoader : null
ExtClassLoader.loadClass :java.lang.String Successful
real ClassLoader : null
name:java.lang.System
try to use ExtClassLoader to load class : java.lang.System
real cls : class java.lang.System
real ClassLoader : null
ExtClassLoader.loadClass :java.lang.System Successful
real ClassLoader : null
name:java.io.PrintStream
try to use ExtClassLoader to load class : java.io.PrintStream
real cls : class java.io.PrintStream
real ClassLoader : null
ExtClassLoader.loadClass :java.io.PrintStream Successful
real ClassLoader : null
Show DataBean!
4.自定义classloader (二)
public
class
TestClassLoader {
public
static
void
main(String[] args)
throws
InstantiationException, IllegalAccessException, ClassNotFoundException {
ClassLoader myLoader =
new
ClassLoader() {
public
Class<?> loadClass(String name)
throws
ClassNotFoundException {
try
{
System.
out
.println(
"name:"
+ name);
if
(name.startsWith(
"java"
)) {
return
super
.loadClass(name);
}
String fileName = name.substring(name.lastIndexOf(
"."
) + 1) +
".class"
;
InputStream is = getClass().getResourceAsStream(fileName);
if
(is ==
null
) {
return
super
.loadClass(fileName);
}
byte
[] b =
new
byte
[is.available()];
is.read(b);
return
defineClass(name, b, 0, b.
length
);
}
catch
(IOException e) {
throw
new
ClassNotFoundException();
}
}
};
Object obj1 = TestClassLoader.
class
.getClassLoader().loadClass(
"sms.TestClassLoader"
).newInstance();
System.
out
.println(obj1.getClass());
System.
out
.println(obj1
instanceof
sms.TestClassLoader);
Object obj2 = myLoader.loadClass(
"sms.TestClassLoader"
).newInstance();
System.
out
.println(obj2.getClass());
System.
out
.println(obj2.getClass().getClassLoader());
System.
out
.println(obj2
instanceof
sms.TestClassLoader);
}
}
运行结果:
class sms.TestClassLoader
true
name:sms.TestClassLoader
name:java.lang.Object
name:java.lang.ClassLoader
name:sms.TestClassLoader$1
class sms.TestClassLoader
sms.TestClassLoader$1@6a998c1
false
最好的办法是不重写loadClass方法,而是重写findClass方法,同样可以达到目的。
这点在ClassLoader的loadClass方法的注释中有提及
*
<p>
Subclasses of
<tt>
ClassLoader
</tt>
are encouraged to override
{@link
* #findClass(String)}, rather than this method.
</p>
重写findClass后,代码如下:
@Override
public
Class<?> findClass(String name)
throws
ClassNotFoundException{
try
{
String fileName = name.substring(name.lastIndexOf(
"."
)+1) +
".class"
;
InputStream is =
this
.getClass().getResourceAsStream(fileName);
byte
[] b =
new
byte
[is.available()];
is.read(b);
return
defineClass(name, b, 0, b.
length
);
}
catch
(IOException e){
throw
new
ClassNotFoundException(name);
}
}