- java.lang.ClassLoader 抽象类,根据类名称,找到类的字节码,加载类,生成Class对象,获取类资源如配置文件
- 引导加载类(bootstrap class loader)
用来加载java的核心类库的,使用原生代码来实现的(c++),并不继承自java.lang.ClassLoader
- 扩展类加载库(extension class loader)
用来java的扩展库,由sunmisc.Launcher$ExtClassLoader实现,java实现,继承自java.lang.ClassLoader
- 应用程序类加载器(application class loader)
根据java应用的类路径(classpath,java.class.path)加载类,由sunmisc.Launcher$AppClassLoader实现,java实现,继承自java.lang.ClassLoader
- 自定义类加载器
通过继承java.lang.ClassLoader实现自己的类加载器 java实现
他们之间的关系是树形结构,但不是继承关系,而是组合使用关系
public class Demo02 {
public static void main(String[] args) {
System.out.println(ClassLoader.getSystemClassLoader());//当前使用的类加载器
System.out.println(ClassLoader.getSystemClassLoader().getParent());
//父亲类加载器,这个父亲指的是属性结构的父亲,不知继承关系
System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
System.out.println(System.getProperty("java.class.path"));//当前类加载path的路径
}
输出
第三行是boostrap class loader,c++实现的所以java中无法访问
}
类加载器的代理模式
双亲委托机制(代理模式的一种)
某个特定的类加载器在接到加载类的请求时,将任务委托给父类(树结构的父类)加载器,直到根节点的类加载器,如果该加载器无法加载类,再一层一层向下加载,直到加载成功,就返回。保证了Java核心库的类型安全,类加载器除了用于加载类,也是最安全的保障。比如java.lang.String类是java的核心类库,你要加载一个String类,采用双亲委托机制就会确保你加载到java核心类库的String类,而不是会有人自己定义的路径为java.lang.String类。
但是并不是所有的类加载器都是用双亲代理模式机制,Tomcat服务器类加载器也是用代理模式,只是不是双亲委托机制,而是自己先去加载,加载不了,再给父类。
线程上下文类加载器
抛弃双亲委托机制,每一个线程都有一个关联的上下文类加载器,默认是系统类加载器,可以用下面第二个方法进行更改,比如更改为自定义的类加载器。
Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader();
自定义类加载器
双亲委派纸质是在loadclass()方法实现的,每次都会让parent来加载类就是调用parent类加载器的findclass()方法
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
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();
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(c);
}
return c;
}
}
不打破双亲委派机制
那么在自己定义类加载器就是继承ClassLoader,重写findClass方法,不打破双亲委派机制,当父类加载类都加载不到这个类,就使用自己类重写的findclass方法,实现自己的功能
打破双亲委派机制
如果要打破双亲委派机制,不仅要重写findClass方法还有重写loadclass方法