ClassLoader类加载器,顾名思义就是将java class文件加载到内存中去的。Java有三种ClassLoader分别是:
- Bootstrap Classloader: 启动类加载器,C++实现。主要加载核心类库。加载JRE_HOME/lib下面的类
- Extention Classloader: 扩展类加载器,加载JRE_HOME/ext目录下面。
- App ClassLoader: 应用类加载器,当前应用的classpath的所有类。 这三个类加载器的加载顺序为启动类加载器->扩展类加载器->应用类加载器 其中Extention Classloader与App Classloader均继承自URLClassLoader。
他们在类的继承关系上没有什么关系,但是在概念上有父子关系。
public class Launcher {
private ClassLoader loader;
public Launcher() {
// Create the extension class loader
ClassLoader extcl;
try {
extcl = ExtClassLoader.getExtClassLoader();
} catch (IOException e) {
throw new InternalError(
"Could not create extension class loader", e);
}
// Now create the class loader to use to launch the application
try {
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader", e);
}
//设置AppClassLoader为线程上下文类加载器,这个文章后面部分讲解
Thread.currentThread().setContextClassLoader(loader);
}
创建AppClassLoader需要以ExtClassLoader为参数。
双亲委派模式
AppClassLoader首先调用ExtClassLoader,ExtClassLoader调用BootStrap Classloader,最终若BootStrap无法加载类,则调用Ext,Ext无法加载则调用App,App无法加载则抛出异常。所有类的加载都遵循相同的流程,由于都是调用Parent加载器,因此称为双亲委派模式。
Classloader加载过程
- loadClass(String,boolean)实现这个方法的步骤如下:
- 执行findLoaderClass(String)检测class是否已经被加载
- 执行父加载器的loadClass方法,若父加载器为null,则jvm内置的Bootstrap加载
- 若向上委托父加载器没有加载成功,则通过findClass(String)查找。
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 首先,检测是否已经加载
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
//父加载器不为空则调用父加载器的loadClass
c = parent.loadClass(name, false);
} else {
//父加载器为空则调用Bootstrap Classloader
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
//父加载器没有找到,则调用findclass
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
//调用resolveClass()
resolveClass(c);
}
return c;
}
}
- 实现一个自定义的classloader,建议覆盖findClass()方法,而不要直接改写loadClass。
自定义ClassLoader
- 编写一个类继承ClassLoader的类。
- 复写findClass()方法。
- 在findClass()方法中调用defineClass(),defindClass将二机制内容转换成Class对象,不符合要求则抛出异常。
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class DiskClassLoader extends ClassLoader {
private String mLibPath;
public DiskClassLoader(String path) {
// TODO Auto-generated constructor stub
mLibPath = path;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
String fileName = getFileName(name);
File file = new File(mLibPath,fileName);
try {
FileInputStream is = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int len = 0;
try {
while ((len = is.read()) != -1) {
bos.write(len);
}
} catch (IOException e) {
e.printStackTrace();
}
byte[] data = bos.toByteArray();
is.close();
bos.close();
return defineClass(name,data,0,data.length);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.findClass(name);
}
//获取要加载 的class文件名
private String getFileName(String name) {
// TODO Auto-generated method stub
int index = name.lastIndexOf('.');
if(index == -1){
return name+".class";
}else{
return name.substring(index+1)+".class";
}
}
}