Java双亲委派机制

一.Java有4种类加载器

  1. Bootstrap ClassLoader(启动类加载器):加载\lib路径下的类库,通常是rt.jar
  2. Extension ClassLoader (扩展类加载器) : 加载\lib\ext路径下的类库
  3. Application ClassLoader(应用程序类加载器):加载用户类路径(classpath)(没有指定的话通常指应用程序的当前目录)上的类库。
  4. User ClassLoader(用户自定义类加载器):继承ClassLoader,加载指定路径的class文件

二. 双亲委派模型的工作过程:

如果一个类加载器收到类加载的请求,它首先不会自己尝试去加载这个类,而是把这个请求委派给父加载器去完成。每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求,子加载器才会尝试自己去加载。

三.为什么要使用双亲委派模型:

  1. 为了保证Java程序的安全,如java.lang.Object是所有类的父类,如果用户自己编写了一个同样限定名的类,放在程序的classpath中,那系统中将会出现多个不同的Object类,Java类型体系中最基础的行为也就无法保证,应用程序也会变得一片换乱。
    所以是为了避免用户自己编写的类动态替换Java的一些核心类。如Object,String
  2. 避免类的重复加载,因为JVM中区分不同类,不仅仅是根据类名,相同的class文件被不同的ClassLoader加载就是不同的两个类。

四. 双亲委派模型的实现代码

java.lang.ClassLoader的loadClass()方法

protected synchronized Class loadClass(String name, boolean resolve) 
throws ClassNotFoundException  {
        //首先检查请求的类是否已经被加载过了
        Class c = findLoadedClass(name);
        if(c == null) {
            try {
              //没有加载则调用父加载器的loadClass方法
                if(parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                //若父加载器为空则默认使用启动器类加载器作为父加载器。
                        c = findBootstrapClassOrNull(name);
                    }
              }
          catch(ClassNotFoundException e){
                //如果父类加载器加载失败,说明父类加载器无法完成加载请求
            }
          if(c == null) {
                  //在父类加载器无法加载的时候
                //再调用本身的findClass()方法来进行类加载
                c = findClass(name);
              }
        }
    if(resolve)  {
          resolveClass(c);
        }
return c;
  }

上面有3个方法需要注意:

  • loadClass: 主要进行类加载的方法,默认的双亲委派机制就实现在这个方法。
  • findClass:根据名字加载字节码
  • defineClass: 把字节码转化成Class类

五.破坏双亲委派模型

双亲委派过程都在loadClass方法内,想要破坏这种机制,重写其中的loadClass方法,使其不进行双亲委派即可。

  • 双亲委派被破坏的例子
  1. 双亲委派出现之前
    JDK1.2之后才引入双亲委派模型,在这之前用户自定义的类加载器肯定是没有遵循双亲委派原则。
  2. JNDI、JBDC等需要加载SPI接口实现类的情况
    JNDI、JDBC通过引入ThreadContextClassLoader(线程上下文加载器,默认就是应用程序类加载器)的方式破坏双亲委派原则。JNDI使用线程上下文加载器去加载所需要的SPI代码,就是父类加载器请求子类加载器去完成类加载的动作,而不是双亲委派模型中先委托父类加载,再由子类加载的原则。

你可能感兴趣的:(Java双亲委派机制)