达内--Java基础进阶――“ClassLoader之二――自定义ClassLoader” (一)

2014-11-24 07:17:15 · 作者: · 浏览: 0

为什么要使用自定义ClassLoader很多时候人们会选择使用自定义的ClassLoader,而不使用系统的ClassLoader。这样做的原因是,在编译时无法预知运行时会需要哪些Class,特别是在一些AppServer中,比如Tomcat、Avalon-Phonix、Jboss;或是程序提供某种插件(Plug-In)的特性,让用户可以在只拥有程序二进制代码的情况下添加自己的功能,比如Ant、
Jxta-shell等。

ClassLoader内部结构通常定制一个ClassLoader很简单,一般只需要很少的几个步骤就可以完成。
Java规范规定,所有的用户自定义ClassLoader都必须从抽象类“java.lang.ClassLoader”类继承而来。下面先看一下这个类的内部实现,以帮助我们更好的理解相关内容。

protected synchronized Class< > loadClass(String name, boolean resolve)

throws ClassNotFoundException

{

// First, check if the class has already been loaded

Class c = findLoadedClass(name);

if (c == null) {

try {

if (parent != null) {

c = parent.loadClass(name, false);

} else {

c = findBootstrapClass0(name);

}

} catch (ClassNotFoundException e) {

// If still not found, then invoke findClass in order

// to find the class.

c = findClass(name);

}

}

if (resolve) {

resolveClass(c);

}

return c;

}
通常我们使用ClassLoader.loadClass(String
name):Class根据指定的类名得到一个相应的Class实例。从Java源代码中我们可以看到,缺省的ClassLoader做了如下的工作: 1. 调用FindLoadedClass(String):Class 检查一下这个Class是否已经被加载过了。由于JVM 规范规定ClassLoader可以在缓存保留它所加载的Class,因此如果一个Class已经被加载过,直接从缓存中获取即可。 2. 调用它的父类的LoadClass()方法,如果它的父类不为空,则使用JVM内部的ClassLoader(即著名的BootstrapClassloader)来加载这个Class。在第10行我们可以看到使用了一个Native方法来调用这个Bootstrap
classloader。 3. 如果上面两步都没有找到,调用findClass(String):Class方法来查找并加载这个Class。 因此我们只要覆盖这个findClass(String):Class方法即可达到定义ClassLoader的要求。
1.FileClassLoader.java
package jack.classloader.own.local;

//Load local class file
import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileInputStream;

public class FileClassLoader extends ClassLoader {

public Class< > findClass(String name){

byte [] data = loadClassData(name);

return defineClass(name, data, 0, data.length);

}

private byte[] loadClassData(String name){

FileInputStream fis = null;

byte [] data = null;

try {

fis = new FileInputStream(

new File(getFinalPath(name)));

ByteArrayOutputStream baos = new ByteArrayOutputStream();

int ch = 0;

while ((ch = fis.read()) != -1) {

baos.write(ch);

}

data = baos.toByteArray();

} catch (Exception e) {

e.printStackTrace();

}

return data;

}

private String getFinalPath(String name){

String finalPath = "";

String path = System.getProperty("user.dir");

String [] nameStrings = name.split("\\.");

String tempStr = "";

for(String str : nameStrings){

tempStr = tempStr + str + File.separatorChar;

}

tempStr = tempStr.substring(0, tempStr.lastIndexOf(File.separatorChar));

finalPath = path + File.separator + "bin" + File.separator + tempStr + ".class";

return finalPath;

}

}
2.RemoteClassLoader.java
package jack.classloader.own.remote;

//Looa remote class file

import java.io.InputStream;

import java.net.URL;

import java.net.URLConnection;

public class RemoteClassLoader extends ClassLoader {

public Class< > findClass(String name){

byte [] data = loadClassData(name);