美文网首页
三、JAVA类加载器

三、JAVA类加载器

作者: lianzf | 来源:发表于2020-02-21 20:03 被阅读0次

    类加载器

    通过类的全限定名来获取描述此类的二进制字节流,把类加载阶段中的这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取需要的类,实现这个动作的代码模块称为“类加载器”。

    public abstract class ClassLoader {
        // 父加载器
        private final ClassLoader parent;
        // 加载类的核心方法之一。如果没找到类则抛出ClassNotFoundException
        protected Class loadClass(Stringname, boolean resolve)throws ClassNotFoundException{
            // synchronized意味着:
            // 1. 同一时间只允许一个线程加载名字为name的类
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has alreadybeen loaded
                // 2. 在加载之前先检查,是否已经加载过该类
                Class c = findLoadedClass(name);
                // 3. c==null代表只有没有被加载过的类才会进行加载
                if (c == null) {
                    long t0 = System.nanoTime();
                    try {
                        // 双亲委派
                        // 父加载器能加载的绝不给子类加载
                        if (parent != null) {
                            // 如果父加载器不为null,则把类加载的工作交给父加载器
                            c = parent.loadClass(name, false);
                        } else {
                            // 如果父加载器为null,则把类加载的工作交给BootstrapClassLoader
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {
                        // ClassNotFoundException thrown if classnot found
                        // from the non-null parent class loader
                    }
                    // 如果父加载器不能加载,子加载器去尝试加载
                    if (c == null) {
                        // If still not found, then invokefindClass 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;
            }
        }
    }

    ClassLoader.loadClass核心代码总结:

    同一时间只允许一个线程加载名字为name的类。
    在加载之前先检查,是否已经加载过该类。只有没有加载过的才允许加载
    双亲委派:父加载器能加载的绝不给子类加载
    父加载器加载不到类的情况,交给子加载器去加载(即:findClass)

    虚拟机类加载器

    从Java虚拟机角度来讲,只存在两种不同的类加载器:一种是启动类加载器(BootstrapClassLoader),由C++语言实现,是虚拟机自身的一部分;另一种是所有其他的类加载器,由Java语言实现,独立于虚拟机外部,全部继承抽象类java.lang.ClassLoader。

    从开发人员角度来看,类加载器大致分一下三种:

    启动类加载器(BootstrapClassLoader):负责将存放在\lib目录中的,或被-Xbootclasspath参数指定的路径中的,并且是虚拟机识别的类库加载到虚拟机中。如,rt.jar。名字不符合即使放在目录中也不被加载。如果需要把加载请求委派给引导类加载器,直接使用null代替即可。
    扩展类加载器(ExtensionClassLoader):由sum.misc.Launcher$ExtClassLoader实现,负责加载<Java_Home>\lib\ext目录中的,或者被java.ext.dir系统变量所指定的路径中的所有类库。开发者可以直接使用扩展类加载器。
    应用程序类加载器(ApplicationClassLoader):由sun.misc.Launcher$App-ClassLoader实现。是ClassLoader中的getSystemClassLoader()方法的返回值,所以也称为系统类加载器。负责加载用户路径(ClassPath)上所指定的类库,如果应用程序中没有自定义过自己的类加载器,这个就是默认的加载器,开发人员可以直接使用这个类加载器。

    自定义类加载器

    自定义加载器有何用途:

    》加密

    Java代码很容易被反编译,如果你需要对你的代码进行加密以防止反编译,则可以将编译后的代码用加密算法加密。但加密后的类就不能再使用Java默认的类加载器进行加载,这时候就需要自定义类加载器。

    》非标准的来源加载代码

    字节码是放在数据库或者网络位置,需要自定义类加载器

    双亲委派

    什么是双亲委派

    如果一个类加载器收到了加载某个类的请求,则该类加载器并不会去加载该类,而是把这个请求委派给父类加载器,因此所有的类加载请求最终都会传送到顶端的启动类加载器;
    只有当父加载器在其搜索范围内无法找到所需的类,并将该结果反馈给子加载器,子加载器会尝试去自己加载。

    总结:父加载器能加载的绝不给子加载器加载,只有父加载器找不到所需的类才让子加载器尝试加载。

    如何打断默认双亲委派机制

    如果想打破双亲委派模型,只需要重写loadClass方法即可。

    为什么使用双亲委派

    对任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。
    判断两个类是否"相等",必须是在这两个类被同一个类加载器加载的前提下。

    基于双亲委派模型设计,那么Java中基础类,如Object类重复多次的问题就不会存在了,因为经过层层传递,加载请求最终都会被BootstrapClassLoader所响应。加载的Object类也会只有一个,否则如果用户自己编写了一个java.lang.Object类,并把它放到了ClassPath中,会出现很多个Object类,这样Java类型体系中最最基础的行为都无法保证,应用程序也将一片混乱。

    相关文章

      网友评论

          本文标题:三、JAVA类加载器

          本文链接:https://www.haomeiwen.com/subject/dgjhqhtx.html