双亲委派机制
双亲委派机制: 我理解的 双亲委派机制 简单来讲就是,类加载器加载类的时候是 自顶向下 的过程来加载。详情如下:
在某个加载器进行类加载是,会逐级向上找到他最终的父类,BootstrapClassLoader 先进行加载,逐级向下进行加载,如果某个父类加载过了则不会重新在加载,如果所有的父类都没有加载过,最后再由自己来进行加载。
类加载器的子父级关系如下(由子到父):
用户自定义类加载器 ->> appClassLoader ->> extClassLoader ->> BootstrapClassLoader
BootstrapClassLoader:根类加载器,负责加载java的核心类,是C++编写的;
ExtensionClassLoader:扩展类加载器,扩展类加载器的加载路径是JDK目录下jre/lib/ext;
AppClassLoader:应用类加载器,它负责在JVM启动时加载来自java命令的-classpath选项、java.class.path系统属性或CLASSPATH环境变量所指定的jar包和类路径。程序可以通过getSystemClassLoader()来获取系统类加载器;
使用双亲委派机制的原因:一方面防止重复加载。一方面保证系统重要类被覆盖。如果我们定义了一个的类叫java.lang.String。那么他和java自带的String类已经重复了,如果加载了我们定义的String类,那么java自己的String类就会失效。在有了双亲委派机制之后,我们自己定义的类是由appClassLoader加载的,而java.lang.String是由BootStarpClassLoader已经加载过的
部分源码如下(我加了中文版注释)
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);
//c==null表示该类没有被加载
if (c == null) {
long t0 = System.nanoTime();
try {
//如果有父类,则优先用父类进行加载。否则说明已经到了最顶层的bootstrapClassLoader,到此则开始加载
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;
}
}
打破双亲委派机制?
1, 正如上述代码描述的,如果我们重写了loadClass方法;(其实“java.” 下的任何包不会受到影响,因为已被设置为必须由BootStarpClassLoader加载,所以就算自定义类加载器加载也会失败)
2,使用线程上下文类加载器(未仔细了解,自行搜索或详见:https://blog.csdn.net/yangcheng33/article/details/52631940);