package com.linuxidc.utils;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ServiceClassLoader extends ClassLoader{
private String classPath;
public ServiceClassLoader(String classPath) {
this.classPath = classPath;
}
/**
* 重写父类的findClass 方法。 父类的loadClass会调用此方法
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> c = null;
byte[] classData = getClassData(name);
if (classData!=null) {
c = defineClass(name, classData, 0, classData.length);
}else {
throw new ClassNotFoundException();
}
return c;
}
// 将class文件通过IO流读取,转化为字节数组
private byte[] getClassData(String name) {
String path = classPath + "/"+ name.replace('.', '/') + ".class";
InputStream iStream = null;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
iStream = new FileInputStream(path);
byte[] buffer = new byte[1024];
int temp = 0;
while ((temp = iStream.read(buffer))!=-1) {
byteArrayOutputStream.write(buffer, 0, temp);
}
if (byteArrayOutputStream!=null) {
return byteArrayOutputStream.toByteArray();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (iStream!=null) {
iStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (byteArrayOutputStream!=null) {
byteArrayOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
对类加载器的使用代码如下:
ServiceClassLoader serviceClassLoader = new ServiceClassLoader("c:\myclass"); Czlass<?> c = ServiceClassLoader.loadClass("com.linuxidc.service.Myclass");
如果用同一个ServiceClassLoader对象去加载同一个Class文件多次,每次加载后的Class对象为同一个! 然而如果new不同的自定义ClassLoader去加载同一个Class文件,则每次会返回不同的Class对象。
注意:不能将所要加载的Class文件放到classpath目录及其任何子目录下,否则会被AppClassLoader优先加载(这是由于类加载采用双亲委派机制,同时AppClassLoader可以加载所有在classpath下的class文件),每次都是同一个AppClassLoader进行加载,因此会出现类缓存问题。
这样就解决了通常在JVM类加载时,直接使用反射出现的类缓存的问题。