ClassLoader的双亲委派机制

双亲委派模型工作过程是:如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。

 1  public Class<?> loadClass(String name) throws ClassNotFoundException {
 2         return loadClass(name, false);
 3     }
 4 
 5     protected Class<?> loadClass(String name, boolean resolve)
 6         throws ClassNotFoundException
 7     {
 8         synchronized (getClassLoadingLock(name)) {
 9             // First, check if the class has already been loaded
10             Class<?> c = findLoadedClass(name);
11             if (c == null) {
12                 long t0 = System.nanoTime();
13                 try {
14                     if (parent != null) {
15                         c = parent.loadClass(name, false);
16                     } else {
17                         c = findBootstrapClassOrNull(name);
18                     }
19                 } catch (ClassNotFoundException e) {
20                     // ClassNotFoundException thrown if class not found
21                     // from the non-null parent class loader
22                 }
23 
24                 if (c == null) {
25                     // If still not found, then invoke findClass in order
26                     // to find the class.
27                     long t1 = System.nanoTime();
28                     c = findClass(name);
29 
30                     // this is the defining class loader; record the stats
31                     sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
32                     sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
33                     sun.misc.PerfCounter.getFindClasses().increment();
34                 }
35             }
36             if (resolve) {
37                 resolveClass(c);
38             }
39             return c;
40         }
41     }

从源码(jdk1.8)中看loadClass这个方法,注释上已经说的很清楚了,调用findLoadedClass方法检查有没有加载过这个类,如果没有就调用parent的loadClass方法,从底层一级级往上。如果找到最后都没有ClassLoader加载过这个类,就调用findClass方法查找这个类,然后又从顶层一级级往下调用findClass方法,如果有自定义ClassLoader的话最后会走到自定义的findClass方法,最终都没找到就抛出ClassNotFoundException。

为什么要使用双亲委派机制去加载类

  1. 比如两个类A和类B都要加载System类:

  • 如果不用委托而是自己加载自己的,那么类A就会加载一份System字节码,然后类B又会加载一份System字节码,这样内存中就出现了两份System字节码。

  • 如果使用委托机制,会递归的向父类查找,也就是首选用Bootstrap尝试加载,如果找不到再向下。这里的System就能在Bootstrap中找到然后加载,如果此时类B也要加载System,也从Bootstrap开始,此时Bootstrap发现已经加载过了System那么直接返回内存中的System即可而不需要重新加载,这样内存中就只有一份System的字节码了。

  1. 如果有人想篡改System类,如String.java,在这种机制下这些系统的类已经被Bootstrap classLoader加载过了,就算自己重写,也总是使用Java系统提供的System,自己写的System类根本没有机会得到加载。从一定程度上防止了危险代码的植入。

posted @ 2019-03-22 16:25  bce1100  阅读(293)  评论(0编辑  收藏  举报