双亲委派
双亲委派
谈到双亲委派会涉及到三种类加载器:
启动类加载器(Bootstrap ClassLoader),这个类加载器底层为c++编写,属于虚拟机一部分。此类加载器用于加载<JAVA_HOME>\lib目录,可以被被-Xbootclasspath参数所指定的路径存放的,能够被虚拟机所识别的类库加载到虚拟机的内存中。而其它类加载器都由Java层实现并继承java.lang.ClassLoader。
执行了了启动类加载器会加载sun.misc.Launcher这个类。此类下有两个静态内部类。
扩展类加载器(Extension ClassLoader)
负责加载<JAVA_HOME>\lib\ext目录下,或者被java.ext.dirs系统变量所指定的路径中所有的类库。
应用程序类加载器(Application ClassLoader)
也被称为“系统类加载器”,负责加载用户类路径java -classpath上的所有类库。如果没有自定义类加载器,
那么这个加载器就是默认的类加载器。可以通ClassLoader的getSystemClassLoader()获取该类加载器的实例。

接下来正式说说双亲委派:当一个类收到了类加载的请求,它不会自己马上去加载这个类,而是把这个请求委派给父类加载器。
每层类加载器都这么做,直到到达最顶层的启动类加载器。如果顶层加载不了,子加载器才会尝试加载这个类。
因为类加载器的类信息存放在方法区的不同区域,所以在加载过程中如果由分别两个不同类加载器各加载一个相同名字的类,这两个类的对象是不同的。

实现:
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; } }
为什么需要双亲委派:
- 每一个类都只会被加载一次,避免了重复加载
- 每一个类都会被尽可能的加载(从引导类加载器往下,每个加载器都可能会根据优先次序尝试加载它)
- 有效避免了某些恶意类的加载(比如自定义了Java。lang.Object类,一般而言在双亲委派模型下会加载系统的Object类而不是自定义的Object类)

浙公网安备 33010602011771号