• ClassLoader简单介绍


    要理解ClassLoader,我们可以通过what、how两个方面来解释

    一、what:什么事ClassLoader?

      1、ClassLoader可以是将class文件加载到JVM方法区。

      2、ClassLoader主要分为2类,用户自定义的类加载器和内部类加载器:启动内装载器(bootstrap)和用户自定义装载器(user-defined class loader)

      启动类装器分为3类:Bootstrap ClassLoader:启动类加载器,是Java类加载层次中最顶层的类加载器,是Extension ClassLoader的父加载器,因为Bootstrap ClassLoader是用c++写的,所有在java代码中无法找到

                该类。主要负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等。

                Extension ClassLoader:称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。

                AppClassLoader:称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。

      3、ClassLoader的加载原理:

        ClassLoader加载类的原理:使用双亲委托机制;当ClassLoader需要加载某个类时,它在搜索该类之前会将搜索的任务交给父加载器试图加载。所以搜索的过程是从Bootstrap ClassLoader——>

        Extension ClassLoader——>Extension ClassLoader——>App ClassLoader依次查找,查到到对应的类,就将该对象加载到JVM中。使用该委托机制主要是为了防止人恶意修改JDK的核心代码,比如你自己创建

        了一个类为String,包名也为java.lang,如果没有委托机制,那么调用String类时可能加载的就是你定义的String类。而不是JDK所提供的String类。二委托机制从Bootstrap ClassLoader开始搜索,在java的核心库

        中找到了该类,就直接将该类加载到JVM中,就不会读取到你所写的String类。

        

    1 //获取当前的类加载器
    2         ClassLoader loader=Thread.currentThread().getContextClassLoader();
    3         System.out.println(loader);
    4         while(loader!=null){
    5             loader=loader.getParent();
    6             System.out.println(loader);
    7         }

        输出结果为:

             

    二、how:如何自定义类加载器

      1、应用场景:我们需要加载网上的class文件到内存中,使用该类实现我们项目所需的业务逻辑。

      2、自定义类加载器分两步:继承ClassLoader类,重写findClass方法

    package edu.test;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.URL;
    
    public class NetWorkClassLoader extends ClassLoader {
    
        private String rootUrl;
    
        public NetWorkClassLoader(String rootUrl) {
            this.rootUrl = rootUrl;
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            Class clazz = null;
            
            byte[] classData = getClassDate(name); // 根据类的二进制名称,获得该class文件的字节码数组
            if (classData == null) {
                throw new ClassNotFoundException();
            }
            clazz = defineClass(name, classData, 0, classData.length); // 将class的字节码数组转换成Class类的实例
    
            return clazz;
        }
    
        // 根据类的二进制名称,获取该class文件的字节码文件
        private byte[] getClassDate(String name) {
            InputStream input = null;
            ByteArrayOutputStream baos = null;
            String path = classNameToPath(name);
            try {
                URL url = new URL(path);
                byte[] buff = new byte[1024 * 4];
                int len = -1;
                input = url.openStream();
                baos = new ByteArrayOutputStream();
                while ((len = input.read(buff)) != -1) {
                    baos.write(buff, 0, len);
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (input == null) {
                    try {
                        input.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            return baos.toByteArray();
        }
    
        private String classNameToPath(String name) {
            return rootUrl + "/" + name.replace(".", "/") + ".class";
        }
    }

        类加载器测试

    public class ClassLoaderTest {  
          
        public static void main(String[] args) {  
            try {   
                String rootUrl = "http://localhost:8080/httpweb/classes";  
                NetWorkClassLoader networkClassLoader = new NetWorkClassLoader(rootUrl);  
                String classname = "org.classloader.simple.NetClassLoaderTest";  
                Class clazz = networkClassLoader.loadClass(classname);  
                System.out.println(clazz.getClassLoader());  
                  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
          
    } 
  • 相关阅读:
    js添加和删除class
    GIT回滚master分支到指定tag版本
    table添加正确的样式
    iframe父页面与子页面赋值
    关于日期转换
    vue-cli脚手架安装
    npm手册
    linear-gradient常用实现效果
    【转载】说说JSON和JSONP,也许你会豁然开朗,含jQuery用例
    雷霄骅走了
  • 原文地址:https://www.cnblogs.com/googlemeoften/p/4737775.html
Copyright © 2020-2023  润新知