Java类加载器

JVM类装载过程

  • 加载-即今天我们要学习的部分,链接部分有机会再研究
  • 链接
    包括:
  1. 验证(Verification),字节码是否满足规范要求
  2. 准备(Preparation),内存分配,常量池初始化
  3. 解析(Resolution),解析类、接口、字段、方法等符号引用
  • 初始化,执行类的初始化方法
  • 研究参考:JVM规范

一、类加载过程

  • 程序是依靠 ,多个Java类共同协作完成的
  • 程序是依靠多个Java类共同协作完成的
  • JVM依据classpath执行的类库的顺序来查找类

1.1引出潜在的问题

  • 如何找到正确的类,如classpath路径的前后?
  • 如何避免恶意的类,如一个假的String类
  • 加载的顺序,如先加载父类,还是子类
  • ……
    待会将会根据这些问题进行一一梳理

二、类加载器ClassLoader

2.1作用:

负责查找、加载、校验字节码的应用程序

2.2包名:

java.lang.ClassLoader

2.3 重要函数及成员
  1. load(String className) 根据名字加载一个类,返回类的实例
  2. defineClass(String name, byte[] b, int off, int len) 将一个字节流定义一个类将,这个流命名为name注册到虚拟机中
  3. findClass(String name) 查找一个类
  4. findLoadedClass(String name) 在已加载的类中,查找一个类
  5. 成员变量 ClassLoader parent;

三、JVM四级类加载器

  • 启动类加载器(Bootstrap), 系统类rt jar(JDK包中的类)
  • 扩展类加载器(Extension),jre/lib/ext
  • 应用类加载器(App), classpath,主要加载应用程序上配置的classpath上的类
  • 用户自定义加载器(Plugin), 程序自定义 自己定义的

在这里插入图片描述

3.1类加载机制-双亲委托模型
  1. 首先判断是否已经加载
  2. 若没有,赵父加载器加载
  3. 若还没有,由当前加载器加载

我们看一下loadClass的源码

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 {//q启动类加载器在C层,name为null
                        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;
        }
}
3.2举例:

就是我们都知道,假如我们函数中使用一个String类,String类是java JDK中的核心类,那假如我们自己定义一个String类?系统是怎么保证只加载使用JDK中的String类,而不使用我们定义的String类呢?

答案: 就是我们上述的双亲委托机制,我们应用中的使用到的类,优先使用到当前应用类加载器(APPClassLoader)的父类加载器,依次往上推,最后使用的我们的启动类加载器 (Bootstrap)来加载,启动类加载器主要加载JDK中的核心类,所以我们使用的JDK中的String类。

3.3优点:

避免我们的JDK核心类被篡改,冒充。JVM的四级加载器和双亲委托机制使得JDK的核心类得到优先加载–引出的问题我们已经解决完了

3.4缺点:

这种双亲委托机制也带了一些问题例如核心的一些JDK的类,无法使用我们自定义的类,JDK中就有这样的类:例如XMLparser JDBC等

当然解决方法还是有的:
添加虚拟机参数 :Xbootclasspath/a:path,将我们自己的类路径配置哪位Bootstrap等级

四、自定义类加载器

简单了解,即我们想要让程序加载我们想要加载的类

  • 我看到Plugin时候想到的是Android开发中的插件,我们只要在AS的项目配置中配置我们需要的插件参数,我们通过gradle进行apk的编译,那么插件里面的内容肯定也要放进apk中。

  • 所以我猜测,*AS里面的gradle应该和我们这里的自定义加载路径类加载器是有点关系的,应该说gradle用到了**自定义类加载器 **

4.1两种自定义类加载器
  1. 自定义加载路径
  2. 自定义类加载器
4.1.1自定义加载路径
  • 弥补加载搜索路径静态的不足
  • JDK提供URLClassLoader,从多个URL(jar或者目录)中加载类
//URL支持http、https、file、jar四种协议
URL url = new URL(“xxxxxx”);
URLClassLoader loader = new URLClassLoader(new URL[]{url});
Class<?> c = loader.loadClass("xxx类名");
4.1.2自定义类加载器
  • 继承ClassLoader类
  • 重写findClass(String name)方法
    还可以在加载过程中修改字节码文件,完成加密解密操作
    自由度比自定义加载路径强,可自行研究
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值