美文网首页
ClassLoader简介

ClassLoader简介

作者: 河北漂 | 来源:发表于2018-03-02 18:15 被阅读0次

    1.什么是Classloader

    我们知道,我们写的java程序会被编译器编译成class文件运行在jvm虚拟机上的,Classloader就是jvm加载class文件的工具。

    当我们new ClassName(),或者使用Class.forName("包路径+类名"),或者使用classloader.loadclass("包路径+类名")的时候,就会触发Classloader去类加载对应的路径去查找*.class,并创建对象。

    正常情况下, 一个classLoader需要两个必要属性:
    parent: 用于指明当前classLoader的父类加载器.
    url: 类命名空间, 用于指明当前classLoader从哪里加载class文件.

    2.Classloader的分类

    2.1 BootstrapClassloader 启动类加载器

    其实类加载器也是java类,也需要被加载。BootstrapClassloader就是最初加载Classloader的加载器。而BootstrapClassloader本身,是JVM启动时自动加载,是被C++启动的。
    BootstrapClassloader 负责加载JDK中的核心类库,主要是JAVA_HOME/lib下的类,如rt.jar、resources.jar、charsets.jar等,这里包括其他的java自带的类加载器。

    2.2 ExtClassloader 扩展类加载器

    主要负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar包。

    2.3 AppClassloader 应用类加载器

    主要负责加载classpath下的类,这里包括用户自己定义的类以及jar包。

    2.4 自定义的类加载器

    继承Classloader类实现自己的类加载器,默认父加载器AppClassloader。
    这里的父加载器,并不是继承关系

    3.Classloader的双亲委派

    3.1什么是双亲委派

    当一个类需要被加载时,当前的类加载器会把加载任务委派给parent加载器,parent加载器又会把加载任务委派给自己parent加载器,以此类推,
    直到最顶层bootStrapClassLoader为止, 如果bootStrapClassLoader在自己的类空间(可以理解成上面提到的url)找到了该类的class文件, 就会去加载该类到内存中. 如果找不到, 会把任务再向下传递回extClassLoader, 让它去尝试加载该类. 依次类推, 直到某个类加载器在自己的类命名空间里找到了该类的class文件, 就会把该类加载进内存。


    classLoader
    3.2双亲委派机制的用处

    双亲委派机制其实是java的一种安全机制,能保证类在内存中只存在一份,所有程序使用的都是这一份, 不会出现自己定义一个String类, 被自己定义的classLoader给加载进来的情况, 因为rt.jar中的String会被最优先加载.

    4.自定义Classloader

    4.1实现方式

    继承Classloader类,然后重写findClass方法,方法内去对应的路径下查找class文件,最后io读入,用defineClass把byte[] 转化为class对象。

    import java.io.ByteArrayOutputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class DqClassLoader extends ClassLoader {
    
        private String rootUrl;
    
        public DqClassLoader(String rootPath) {
            this.rootUrl = rootPath;
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            Class clazz = null;
            //根据类的二进制名称,获得该class文件的字节码数组
            byte[] classData = getClassData(name);
            if (classData == null) {
                throw new ClassNotFoundException();
            }
            //将class的字节码数组转换成Class类的实例
            clazz = defineClass(name, classData, 0, classData.length);
            return clazz;
        }
    
        private byte[] getClassData(String name) {
            InputStream is = null;
            try {
                String path = classNameToPath(name);
                is = new FileInputStream(path);
                byte[] buff = new byte[1024 * 4];
                int len = -1;
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                while ((len = is.read(buff)) != -1) {
                    baos.write(buff, 0, len);
                }
                return baos.toByteArray();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;
        }
    
        private String classNameToPath(String name) {
            return rootUrl + "/" + name.replace(".", "/") + ".class";
        }
    }
    
    4.2 自定义加载器的应用场景

    最常见的应用就是 Apache Tomcat 中的WebClassLoader,每个 Web 应用都有一个对应的类加载器实例。所不同的是它是首先尝试去加载某个类,如果找不到再代理给父类加载器。这与一般类加载器的顺序是相反的。其目的是使得 Web 应用自己的类的优先级高于 Web 容器提供的类。
    当然,Java 核心库的类是不在查找范围之内的。这也是为了保证 Java 核心库的类型安全。

    5.结尾

    类加载器是 Java 语言的一个创新。它使得动态安装和更新软件组件成为可能。
    在开发自己的类加载器的时候,需要注意与已有的类加载器组织结构的协调。

    相关文章

      网友评论

          本文标题:ClassLoader简介

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