• Java 类加载ClassLoader学习心得


    本文是笔者在学习Java 类加载的过程中,整理的心得体会,共勉!

    类加载的意义

    简单概念:

    将Java类的.class文件中的二进制数据读入到内存中,放置在运行时数据区的方法区内。

    什么时候会进行类加载?

             本地系统加载;

             代理加载,比如Spring的AOP动态代理;

             从jar包中加载;

             等等等等

    ClassLoader类结构介绍

    ClassLoader是一个抽象类,核心方法如下:

    defineClass():目的是将byte字节流解析成JVM能够识别的Class对象。

    findClass():此方法支持重载,与defineClass()配合使用,目的是获取Class对象的字节码。这个方法的意义在于,我们不仅仅可以通过class文件实例化对象,也可以通过其他方式,比如从网络上获取的字节码文件,可能会有对应的加密规则。

    loadClass():此方法支持重载,目的是获取加载类的类对象。

    resolveClass():实现让JVM链接这个类,此方法调用的是本地方法,不能重载。

    Class类的生命周期

     

    此生命周期对应到ClassLoader类的具体方法:
    加载:loadClass()、findClass()、defineClass()

    连接:包括验证、准备、解析:resolveClass() 本地native方法

    初始化:JVM负责

    类加载机制(双亲委托)

    概念介绍:

    大致的ClassLoader分类:

    1. Bootstrap ClassLoader:负责加载存放在 JDKjrelib(JDK代表JDK的安装目录,下同)下,或被 -Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库
    2. ExtClassLoader:负责加载 JDKjrelibext目录中,或者由 java.ext.dirs系统变量指定的路径中的所有类库(如javax.开头的类),开发者可以直接使用扩展类加载器
    3. AppClassLoader:负责加载用户类路径(ClassPath)所指定的类,其父类是ExtClassLoader

    心得体会:

      这里的父加载器与子加载器 在java类关系上并不是继承关系;

      实现自己的类加载器,不管是直接实现抽象类ClassLoader,还是继承其他子类,父加载器都是AppClassLoader;

    类加载的方式

    1、命令行启动应用时候由JVM初始化加载

    2、通过Class.forName()方法动态加载

    3、通过ClassLoader.loadClass()方法动态加载

    Class.forName()ClassLoader.loadClass()区别

    Class.forName():将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块;

    ClassLoader.loadClass():只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。

    Class.forName(name,initialize,loader)带参函数也可控制是否加载static块。并且只有调用了newInstance()方法采用调用构造函数,创建类的对象 

    应用实践

    实现自定义的ClassLoader

    基于上面对于类加载器的分析,自定义ClassLoader的情况如下:

    1. 需要在自定义路径下查找自定义的class文件
    2. 对我们想要加载的类做特殊处理,比如通过网络传输的类的字节码可能进行了加密,获取这种类的字节码需要在我们自定义的ClassLoader中实现
    3. 实现类的热部署

    从上面的分析我们还可以得到,自定义ClassLoader的实现思路可以通过继承ClassLoader类,重写findClass()来实现,当然你也可以重写loadClass(),但是默认的loadClass()是实现类加载双亲委托模式的,除非你想要破坏这种双亲委托模式,不然就别重写了。

    下面是我在本机写的测试自定义ClassLoader的Demo:

    /**
     * 自定义路径下的class文件加载
     * @Auther: trey_stao@163.com
     * @Date: 2018/5/31 19:34
     * @Description:
     */
    public class PathClassLoader extends ClassLoader {
        private String classPath;
    
        public PathClassLoader(String classPath) {
            this.classPath = classPath;
        }
    
        private String packageName = "com.trey.classloader.Test";
    
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            if(packageName.startsWith(name)) {
                byte[] classData = getData(name);
                if(classData == null) {
                    throw new ClassNotFoundException();
                } else {
                    System.out.println("当前类加载器:"+this.getClass().getClassLoader().toString());
                    return defineClass(name, classData, 0, classData.length);
                }
            } else {
                return super.loadClass(name);
            }
        }
    
        private byte[] getData(String name) {
            String path = classPath + File.separatorChar + name.replace('.',File.separatorChar) + ".class";
            try {
                InputStream is = new FileInputStream(path);
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                byte[] buffer = new byte[2048];
                int num = 0;
                while ((num = is.read(buffer)) != -1) {
                    stream.write(buffer, 0, num);
                }
                return stream.toByteArray();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    实现类的热部署

    这是给自己布置的对类加载学习的总结练习。下面说下自己准备实现的思路:

    1. 实现一个server服务,监听具体目录下的所有class文件的更新情况
    2. 当出现class文件更新时,使用自定义的classLoader进行加载

    参考文献

      整理这篇学习心得时,参考了一些文章,特在此注明,表示感谢!

      周志明:《深入理解Java虚拟机:JVM高级特性与最佳实践》

      纯洁的微笑:java类的加载机制

      许令波:《深入分析Java Web 技术内幕》

  • 相关阅读:
    part17 一些知识总结
    part16 php面向对象
    part15 php函数
    part14 php foreach循环
    part13 数组排序
    part12 php数组
    part11 php条件语句
    part10 php运算符
    part09 php字符串变量
    part08 php常量
  • 原文地址:https://www.cnblogs.com/trey/p/9141035.html
Copyright © 2020-2023  润新知