双亲委派机制
双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。
双亲委派机制:
-
1、当
AppClassLoader
加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader
去完成。 -
2、当
ExtClassLoader
加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。 -
3、如果
BootStrapClassLoader
加载失败(例如在$JAVA_HOME/jre/lib
里未查找到该class),会使用ExtClassLoader
来尝试加载; -
4、若ExtClassLoader也加载失败,则会使用
AppClassLoader
来加载,如果AppClassLoader
也加载失败,则会报出异常ClassNotFoundException
。
-
启动类(根)加载器 Bootstrap ClassLoader
-
扩展类的加载器 ExtClassLoader
-
应用程序加载器 AppClassLoader
ClassLoader源码分析:
public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } 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 { //如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方法native Class findBootstrapClass(String name) 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; } }
-
避免类的重复加载
-
保护程序安全,防止核心API被随意篡改
-
自定义类:java.lang.String
-
自定义类:java.lang.MeDsh(java.lang包需要访问权限,阻止我们用包名自定义类)
-