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);
-
-
name = "jack.classloader.test." + name;
-
-
return defineClass(name, data, 0, data.length);
-
-
}
-
-
-
-
private byte[] loadClassData(String name){
-
-
byte [] data = null;
-
-
try {
-
-
URL urlRemote = new URL("" + name + ".class");//须保证远程文件地址可达
-
-
URLConnection uConnection = urlRemote.openConnection();
-
-
InputStream inputStream = uConnection.getInputStream();
-
-
int length = uConnection.getContentLength();
-
-
data = new byte[length];
-
-
inputStream.read(data);
-
-
inputStream.close();
-
-
return data;
-
-
} catch (Exception e) {
-
-
System.out.println(name +"类没有找到!");
-
-
e.printStackTrace();
-
-
}
-
-
return data;
-
-
}
-
- }
3.MyApp.java
- package jack.classloader.own;
-
-
import jack.classloader.own.local.FileClassLoader;
-
import jack.classloader.own.remote.RemoteClassLoader;
-
import jack.classloader.test.IService;
-
-
public class MyApp {
-
-
/**
-
* @param args
-
* @throws IllegalAcces***ception
-
* @throws InstantiationException
-
*/
-
@SuppressWarnings("unchecked")
-
public static void main(String[] args) throws InstantiationException, IllegalAcces***ception {
-
//local
-
FileClassLoader loader = new FileClassLoader();
-
Class<?> objClass = loader.findClass("jack.classloader.test.Service");
-
IService service = (IService)objClass.newInstance();
-
System.out.println(objClass.getName());
-
System.out.println(objClass.getClassLoader());
-
System.out.println(service);
-
service.service();
-
-
System.out.println();
-
//remote
-
RemoteClassLoader remoteLoader = new RemoteClassLoader();
-
Class<?> objClassRemote = remoteLoader.findClass("Service");
-
IService serviceRemote = (IService)objClassRemote.newInstance();
-
serviceRemote.service();
-
}
-
- }