zoukankan      html  css  js  c++  java
  • 自定义类加载器

      一、类加载器分类

      二、ClassLoader 的类加载机制

      三、自定义类加载器

    一、类加载器分类

     类加载器作用: Java 程序在运行的时候,JVM 通过类加载机制(ClassLoader)把 class 文件加载到内存中,只有 class 文件被加载入内存,才能被其他的 class 引用,使程序正确运行起来

    (1)Bootstrap ClassLoader

    启动类加载器,负责加载 Java 基础类,对应的文件是 %JRE_HOME%/lib 目录下的 rt.jar 、resources.jar 、charsets.jar 、class 等

    (2)Extension ClassLoader

    Java 类,继承自 URLClassLoader 扩展类加载器,对应的文件是 %JRE_HOME%/lib/ext 目录下的 jar 和 class 等

    (3)APP ClassLoader

    Java 类,继承自URLClassLoader 系统类加载器,对应的文件是应用程序 classpath 目录下的所有 jar 和 class 等

     二、ClassLoader 的类加载机制

    Java 的加载机制是双亲委派机制来加载类?

    原因: 这是为了保证如果加载的类是一个系统类,那么会优先由Bootstrp ClassLoader 、Extension ClassLoader 先去加载,而不是使用我们自定义的 ClassLoader 去加载,保证系统的安全

    三种类加载器存在父子关系,APP ClassLoader 的父类加载器是 Extension ClassLoader ,Extension ClassLoader 的父类加载器是 Bootstrap ClassLoader ,要注意的一点是这里并不是继承关系

    当类加载器需要加载一个类时,会先委托它的父类加载器尝试加载,一直往上,如果最顶级的父类加载器没有找到改类,那么委托者自己加载

     只有被同一个类加载器实例加载并且文件名相同的class 文件才被认为是同一个class 

     三、自定义类加载器

     3.1 为何要自定义 ClassLoader

    因为系统的 ClassLoader 只会加载指定目录下的 class 文件,如果想加载自己的 class 文件,就可以自定义一个 ClassLoader

    3.2 如何自定义 ClassLoader 

     新建一个类继承 Java.lang.ClassLoader ,并重写 findClass 方法

    public class MyClassLoader extends ClassLoader{
    
        /**
         * 指定路径
         */
        private String path;
    
        public MyClassLoader(String path) {
            this.path = path;
        }
        /**
         *
         * @param name 类的全路径名称
         * @return
         * @throws ClassNotFoundException
         */
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            Class log = null;
            //获取改 class 文件字节码数组
            byte[] classData = getData();
    
            if(classData != null){
                log = defineClass(name,classData,0,classData.length);
            }
            return log;
        }
    
        /**
         * 将 class 文件转换为字节码数组
         */
        private byte[] getData(){
            File file = new File(path);
            if(file.exists()){
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
    
                try {
                    in = new FileInputStream(file);
                    out = new ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int size = 0;
                    while ((size = in.read(buffer)) != -1) {
                        out.write(buffer, 0, size);
                    }
                }catch (IOException e){
                    e.printStackTrace();
                }finally {
                    try{
                        in.close();
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }
                return out.toByteArray();
            }else {
                return  null;
            }
        }
    }

    可以再getData 里做很多事情,比如加密解密之类的

    创建一个class类

    public class Log {
    
        public static void main(String []args){
            System.out.println("Hello,World");
        }
    }

     使用自定义类加载器加载

    public class MyClassMain {
        public static void main(String []args) throws Exception{
    
    
             String classPath = "D:\app\Log.class";
    
             MyClassLoader myClassLoader = new MyClassLoader(classPath);
    
             String packageNamePath = "com.Log";
    
             Class<?> myClass = myClassLoader.loadClass(packageNamePath);
    
             System.out.println("类加载器:"+myClass.getClassLoader());
    
             //利用反射获取方法
            Method method = myClass.getDeclaredMethod("main",String[].class);
    
            Object o = myClass.newInstance();
    
            String[] arg = {"ad"};
    
            method.invoke(o,(Object)arg);
    
        }
    }

    输出如下

    ClassLoader类是一个抽象类,但却没有包含任何抽象方法。
    如果要实现自己的类加载器且不破坏双亲委派模型,只需要继承ClassLoader类并重写findClass方法。
    如果要实现自己的类加载器且破坏双亲委派模型,则需要继承ClassLoader类并重写loadClass,findClass方法。

    参考:https://blog.csdn.net/huazai30000/article/details/85296671

    参考:https://www.jianshu.com/p/f2ae00d64fa6

  • 相关阅读:
    转 new和malloc的区别
    转 内联函数
    转 C++宏定义详解
    转 内联函数和宏定义的区别
    转 C++中不能声明为虚函数的有哪些函数
    转 PV操作简单理解
    转 Python执行系统命令的方法
    转 常量指针和指针常量的区别详解
    转 python语法学习面向对象之继承
    Singleton、MultiThread、Lib——实现单实例无锁多线程安全API
  • 原文地址:https://www.cnblogs.com/bytecodebuffer/p/12148432.html
Copyright © 2011-2022 走看看