美文网首页
Java 自定义 ClassLoader 实现 JVM 类加载

Java 自定义 ClassLoader 实现 JVM 类加载

作者: 田真的架构人生 | 来源:发表于2019-06-05 10:23 被阅读0次

    原文:https://mp.weixin.qq.com/s/RaFIPhG1y1kmhue--MD-EQ

    • 定义需要加载的类

    • 定义类加载器

    • 编译需要加载的类文件

    • 编译自定义的类加载器并执行程序

    • 总结

    定义需要加载的类
    为了能够实现类加载,并展示效果,定义一个Hello类,再为其定义一个sayHello()方法,加载Hello类之后,调用它的sayHello()方法。

    public class Hello {
        public static void sayHello(){
            System.out.println("Hello,I am ....");
        }
    }
    

    定义类加载器
    自定义加载器,需要继承ClassLoader,并重写里面的findClass(String name) 方法。

    public class MyClassLoader extends ClassLoader {
        /**
         * 重写父类方法,返回一个Class对象
         * ClassLoader中对于这个方法的注释是:
         * This method should be overridden by class loader implementations
         */
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            Class clazz = null;
            String classFilename = name + ".class";
            File classFile = new File(classFilename);
            if (classFile.exists()) {
                try (FileChannel fileChannel = new FileInputStream(classFile)
                        .getChannel();) {
                    MappedByteBuffer mappedByteBuffer = fileChannel
                            .map(MapMode.READ_ONLY, 0, fileChannel.size());
                    byte[] b = mappedByteBuffer.array();
                    clazz = defineClass(name, b, 0, b.length);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (clazz == null) {
                throw new ClassNotFoundException(name);
            }
            return clazz;
        }
    
        public static void main(String[] args) throws Exception{
            MyClassLoader myClassLoader = new MyClassLoader();
            Class clazz = myClassLoader.loadClass(args[0]);
            Method sayHello = clazz.getMethod("sayHello");
            sayHello.invoke(null, null);
        }
    }
    

    编译需要加载的类文件
    类加载的时候加载的是字节码文件,所以需要预先把定义的Hello类编译成字节友文件。

    javac Hello.java
    

    编译自定义的类加载器并执行程序

    编译代码
    javac MyClassLoader.java
    当然我们也可以同时编译我们所有的java源文件
    javac *.java
    

    执行成功之后,我们用下面的语句执行代码,测试是否成功,并查看结果

    java MyClassLoader Hello
    运行结果
    Hello,I am ....
    

    当程序按照预期显示,就证明我自定义类加载器成功了。

    总结
    通过上面的程序代码,简单的实现JVM的类加载过程,知道了程序运行的一点流程。但是在编写的时候有如下坑需要注意:

    • 类文件不需要指定包,否则加载的时候我们需要额外的处理,把包中的"."替换成文件系统的路径"/"。

    • 需要加载的Hello类中的反射调用的方法要用static修饰,这样invoke的时候第一个参数才可以使用null关键字代替,否则需要创建一个对应的类实例。
      官方文档中有这样一句话If the underlying method is static, then the specified obj argument is ignored. It may be null.

    相关文章

      网友评论

          本文标题:Java 自定义 ClassLoader 实现 JVM 类加载

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