美文网首页
自定义类加载器

自定义类加载器

作者: 书唐瑞 | 来源:发表于2022-03-22 00:11 被阅读0次
    // 待类加载的类
    package com.infuq;
    public class Ticket { }
    

    自定义类加载器 MyClassLoader

    package com.infuq;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    /**
     * 自定义类加载器
     *
     * 加载指定路径scanPath下的类文件
     *
     */
    public class MyClassLoader extends ClassLoader {
    
        // MyClassLoader可以扫描的路径. 例如: /usr/include
        private final String scanPath ;
    
    
        public MyClassLoader(String scanPath){
            super();
            this.scanPath = scanPath;
        }
    
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
    
            byte[] classData = readFileData(name);
    
            if (classData != null) {
                return this.defineClass(name, classData, 0, classData.length);
            }
    
            return null;
        }
    
    
        // 读取clazzName对应的文件内容, 返回字节数组
        private byte[] readFileData(String clazzName) {
    
            File file;
    
            /*
             * 假如scanPath=/usr/include
             * 由于入参clazzName是类的全限定名, 例如java.lang.Object
             * 为了读取clazzName对应的文件, 需要将字符串`java.lang.Object`转成`java/lang/Object`
             * 最后得到完整文件路径/usr/include/java/lang/Object.class
             */
            if (System.getProperty("os.name").contains("Windows")) {
                clazzName = clazzName.replace(".", "\\");
                file = new File(scanPath + "\\" + clazzName + ".class");
            }
            else {
                clazzName = clazzName.replace(".", "/");
                file = new File(scanPath + "/" + clazzName + ".class");
            }
    
    
            // 读取
            if (file.exists()) {
                FileInputStream in = null;
                ByteArrayOutputStream out;
                try {
                    in = new FileInputStream(file);
                    out = new ByteArrayOutputStream();
    
                    byte[] buffer = new byte[1024];
                    int size;
                    while ((size = in.read(buffer)) != -1) {
                        out.write(buffer, 0, size);
                    }
    
                    return out.toByteArray();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (in != null) {
                            in.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            return null;
    
        }
    }
    
    

    测试类 Example

    
    package com.infuq;
    
    import java.util.Scanner;
    
    public class Example {
    
        public static void main(String[] args) throws Exception {
    
            System.out.print("请输入类加载的路径: ");
            Scanner scanner = new Scanner(System.in);
    
            /*
             * 从命令行读取指定扫描的路径
             * 例如
             * Unix : /usr/bin/
             * Windows : D:\\repository\\class
             */
            String scanPath = scanner.next();
            MyClassLoader myClassLoader = new MyClassLoader(scanPath);
    
            /*
             * 读取类的全限定名, 例如 java.lang.Object
             *
             */
            System.out.print("请输入待加载的类全限定名称: ");
            String packageNamePath = scanner.next();
    
    
            System.out.println();
            Class<?> clazz = myClassLoader.loadClass(packageNamePath);
            if (clazz != null)
                System.out.println(packageNamePath + "类加载器是: " + clazz.getClassLoader());
            
            System.out.println("系统类加载器扫描文件路径: " + System.getProperty("java.class.path"));
    
        }
    
    }
    
    

    编译 Ticket.java , MyClassLoader.java , Example.java 三个源文件, 文件结构图如下

    文件结构图

    以上源文件在 /Users/infuq/Repository/GitLab/infuq-others/Lab/2022-3-22 目录下

    其中还把待加载的Ticket.class文件拷贝一份到了自定义的JAVA-INF目录下, 后面会用到

    【测试一】

    image.png

    本计划让自定义类加载器MyClassLoader 加载/Users/infuq/Repository/GitLab/infuq-others/Lab/2022-3-22/JAVA-INF目录下的com.infuq.Ticket类, 根据双亲委派, 委派给了系统类加载器. 而当前目录下就有一个com.infuq.Ticket类, 因此这个Ticket类被系统类加载器加载了.

    改个名称, 故意让系统类加载器找不到Ticket类


    image.png

    继续上面的相同执行


    image.png

    这个时候com.infuq.Ticket就被自定义类加载器加载了.

    相关文章

      网友评论

          本文标题:自定义类加载器

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