由于最近的一个项目需要使用到java的反射机制,所以最近也是好好看了一下java的ClassLoader,目前也只完成了一个可以读取某一个文件夹中的所有类的Loader.
我们都知道,自定义的ClassLoader都是需要重写几个方法的,比如:findResource.findClass.但是很少有文章详细的所以下ClassLoader的调用顺序.先说一下代码吧:
public class MyClassLoader extends ClassLoader {
private String BaseDir = new String();
Logger logger = Logger.getLogger("MyClassLoader");
/**
* @param name 形如"java.lang.String"的字符串
* {@inheritDoc}
*/
@Override
protected Class<?> findClass(String name)
throws ClassNotFoundException {
logger.log(Level.INFO, "findClass");
byte[] bytes = loadClassBytes(name);
Class theClass = defineClass(name, bytes, 0, bytes.length);
if (theClass == null)
throw new ClassFormatError();
return theClass;
}
private byte[] loadClassBytes(String className) throws
ClassNotFoundException {
logger.log(Level.INFO, "loadClassBytes");
try {
String classFile = getClassFile(className);
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();
} catch (IOException fnfe) {
throw new ClassNotFoundException(className);
}
}
private String getClassFile(String name) {
logger.log(Level.INFO, "getClassFile");
StringBuffer sb = new StringBuffer(getBaseDir());
name = name.replace('.', File.separatorChar) + ".class";
sb.append(File.separator + name);
return sb.toString();
}
private String getBaseDir() {
return BaseDir;
}
public void setBaseDir(String basedir){
BaseDir = basedir;
}
// 新增的一个findResource方法
@Override
protected URL findResource(String name) {
logger.log(Level.INFO, "findResource");
try {
URL url = super.findResource(name);
if (url != null)
return url;
url = new URL("file:///" + converName(name));
// 简化处理,所有资源从文件系统中获取
return url;
} catch (MalformedURLException mue) {
throw new RuntimeException(mue);
}
}
private String converName(String name) {
logger.log(Level.INFO, "converName");
StringBuffer sb = new StringBuffer(getBaseDir());
name = name.replace('.', File.separatorChar);
sb.append(File.separator + name);
return sb.toString();
}
}
这就是全部的代码,然后我们在main函数里调用load函数,会出现以下内容:
我们可以看到,Loader函数的执行顺序是: findClass–>loadClassBytes–>getClassFile.所以,如果我们需要自定义我们自己的ClassLoader只需要按着顺序进行修改就行了.
至于main函数吧,就是这样的:
MyClassLoader classLoader = new MyClassLoader();
classLoader.setBaseDir("Classes/");
Class<?> class1 = classLoader.loadClass("test");
for (Method method : class1.getMethods()) {
System.out.println(method.getName());
}
Method method = class1.getMethod("sayHello", null);
method.invoke(class1.newInstance(), null);
我把所有的class文件放在Classes文件夹之下,看上去是这样的:
这是test.class的代码:
public class test{
public static void main(String[] args){
System.out.println("Hello World!");
}
public void sayHello(){
System.out.println("Hello World!");
}
}
于是这样,我们得到了好的结果:

