【jvm】02-手写自己的类加载器

【jvm】02-手写自己的类加载器

欢迎关注b站账号/公众号【六边形战士夏宁】,一个要把各项指标拉满的男人。该文章已在github目录收录。
屏幕前的大帅比大漂亮如果有帮助到你的话请顺手点个赞、加个收藏这对我真的很重要。别下次一定了,都不关注上哪下次一定。

1.简单手写自己的类加载器

创建一个类继承ClassLoader,然后重写findClass、loadClass这两个方法

findClass的方法

private static byte[] loadByte(String name) throws Exception {
    name = name.replaceAll("\\.", "/");
    FileInputStream fis = new FileInputStream(classPath + "/" + name
            + ".class");
    int len = fis.available();
    byte[] data = new byte[len];
    fis.read(data);
    fis.close();
    return data;
}

protected Class<?> findClass(String name) throws ClassNotFoundException {
    try {
        byte[] data = loadByte(name);
        //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。
        return defineClass(name, data, 0, data.length);
    } catch (Exception e) {
        e.printStackTrace();
        throw new ClassNotFoundException();
    }
}

loadClass直接复制ClassLoader中的方法然后把错误的行数删除就行了
重点改动代码如下,让该自己的加载器加载指定包的文件,注意需要提前编译java文件为class

if (name.startsWith("com.example.demo.lesson")) {
    c = findClass(name);
} else {
    c = this.getParent().loadClass(name);
}

2.加载一个和jdk中同名的类

创建一个java.lang.Byte的类,然后用自己的类加载器去加载,然后就触发了jdk的沙箱机制,报了一个安全错误

tomcat的类加载器逻辑

如图所示,这里的核心其实就是每一个war包的代码即使含有同名的类也可以加载
做法如下,自己的classloader复制一份然后加载同一个class文件,可以看到启用的是不同的加载器,都被加载了

3.完整代码

package com.example.demo.lesson.jvm.myloader;

import java.io.FileInputStream;

/**
 * @author seal email:876651109@qq.com
 * @date 2020/9/1 7:23 PM
 * @description
 */
public class MyClassLoaderDemo {

    public static void main(String[] args) throws ClassNotFoundException {
        // Class clazz1 = new MyClassLoader().loadClass("com.example.demo.lesson.jvm.loader.A",false);
        //Class clazz1 = new MyClassLoader().loadClass("java.lang.Byte",false);
        Class clazz2 = new MyClassLoader2().loadClass("com.example.demo.lesson.jvm.loader.A",false);
        System.out.println(new MyClassLoaderDemo().getClass().getClassLoader());
        // System.out.println(clazz1.getClassLoader());
        System.out.println(clazz2.getClassLoader());
    }

    public static String classPath = "F:\\IdeaProjects\\TechingCode\\demoGrace\\src\\main\\java";
    private static byte[] loadByte(String name) throws Exception {
        name = name.replaceAll("\\.", "/");
        FileInputStream fis = new FileInputStream(classPath + "/" + name
                + ".class");
        int len = fis.available();
        byte[] data = new byte[len];
        fis.read(data);
        fis.close();
        return data;
    }

    static class MyClassLoader extends ClassLoader {

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] data = loadByte(name);
                //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }

        @Override
        protected Class<?> loadClass(String name, boolean resolve)
                throws ClassNotFoundException {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    if (name.startsWith("java.lang.Byte")) {
                        c = findClass(name);
                    } else {
                        c = this.getParent().loadClass(name);
                    }
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        long t1 = System.nanoTime();
                        c = findClass(name);

                        // this is the defining class loader; record the stats
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    }

    static class MyClassLoader2 extends ClassLoader {

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] data = loadByte(name);
                //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }

        @Override
        protected Class<?> loadClass(String name, boolean resolve)
                throws ClassNotFoundException {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    if (name.startsWith("com.example.demo.lesson")) {
                        c = findClass(name);
                    } else {
                        c = this.getParent().loadClass(name);
                    }
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        long t1 = System.nanoTime();
                        c = findClass(name);

                        // this is the defining class loader; record the stats
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    }
}

4.ConstantPool

Constant pool:
    #1 = Methodref          #2.#3         // java/lang/Object."<init>":()V
    #2 = Class              #4            // java/lang/Object
    #3 = NameAndType        #5:#6         // "<init>":()V
    #4 = Utf8               java/lang/Object
    #5 = Utf8               <init>
    #6 = Utf8               ()V
    #7 = Fieldref           #8.#9         // com/example/demo/lesson/jvm/construction/Master.master2:Lcom/example/demo/lesson/jvm/construction/Master;
    #8 = Class              #10           // com/example/demo/lesson/jvm/construction/Master
    #9 = NameAndType        #11:#12       // master2:Lcom/example/demo/lesson/jvm/construction/Master;
   #10 = Utf8               com/example/demo/lesson/jvm/construction/Master
   #11 = Utf8               master2
   #12 = Utf8               Lcom/example/demo/lesson/jvm/construction/Master;
   #13 = Fieldref           #8.#14        // com/example/demo/lesson/jvm/construction/Master.master4:Lcom/example/demo/lesson/jvm/construction/Master;
   #14 = NameAndType        #15:#12       // master4:Lcom/example/demo/lesson/jvm/construction/Master;
   #15 = Utf8               master4
   #16 = Fieldref           #8.#17        // com/example/demo/lesson/jvm/construction/Master.int2:I
   #17 = NameAndType        #18:#19       // int2:I
   #18 = Utf8               int2
   #19 = Utf8               I
   #20 = Fieldref           #8.#21        // com/example/demo/lesson/jvm/construction/Master.int4:I
   #21 = NameAndType        #22:#19       // int4:I
   #22 = Utf8               int4
   #23 = Methodref          #24.#25       // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #24 = Class              #26           // java/lang/Integer
   #25 = NameAndType        #27:#28       // valueOf:(I)Ljava/lang/Integer;
   #26 = Utf8               java/lang/Integer
   #27 = Utf8               valueOf
   #28 = Utf8               (I)Ljava/lang/Integer;
   #29 = Fieldref           #8.#30        // com/example/demo/lesson/jvm/construction/Master.integerMax2:Ljava/lang/Integer;
   #30 = NameAndType        #31:#32       // integerMax2:Ljava/lang/Integer;
   #31 = Utf8               integerMax2
   #32 = Utf8               Ljava/lang/Integer;
   #33 = Fieldref           #8.#34        // com/example/demo/lesson/jvm/construction/Master.integerMax4:Ljava/lang/Integer;
   #34 = NameAndType        #35:#32       // integerMax4:Ljava/lang/Integer;
   #35 = Utf8               integerMax4
   #36 = Fieldref           #8.#37        // com/example/demo/lesson/jvm/construction/Master.integerMin2:Ljava/lang/Integer;
   #37 = NameAndType        #38:#32       // integerMin2:Ljava/lang/Integer;
   #38 = Utf8               integerMin2
   #39 = Fieldref           #8.#40        // com/example/demo/lesson/jvm/construction/Master.integerMin4:Ljava/lang/Integer;
   #40 = NameAndType        #41:#32       // integerMin4:Ljava/lang/Integer;
   #41 = Utf8               integerMin4
   #42 = String             #43           // str25
   #43 = Utf8               str25
   #44 = Fieldref           #8.#45        // com/example/demo/lesson/jvm/construction/Master.str2:Ljava/lang/String;
   #45 = NameAndType        #46:#47       // str2:Ljava/lang/String;
   #46 = Utf8               str2
   #47 = Utf8               Ljava/lang/String;
   #48 = String             #49           // str27
   #49 = Utf8               str27
   #50 = Fieldref           #8.#51        // com/example/demo/lesson/jvm/construction/Master.str4:Ljava/lang/String;
   #51 = NameAndType        #52:#47       // str4:Ljava/lang/String;
   #52 = Utf8               str4
   #53 = Class              #54           // java/lang/String
   #54 = Utf8               java/lang/String
   #55 = String             #56           // str30
   #56 = Utf8               str30
   #57 = Methodref          #53.#58       // java/lang/String."<init>":(Ljava/lang/String;)V
   #58 = NameAndType        #5:#59        // "<init>":(Ljava/lang/String;)V
   #59 = Utf8               (Ljava/lang/String;)V
   #60 = Fieldref           #8.#61        // com/example/demo/lesson/jvm/construction/Master.strN2:Ljava/lang/String;
   #61 = NameAndType        #62:#47       // strN2:Ljava/lang/String;
   #62 = Utf8               strN2
   #63 = String             #64           // str32
   #64 = Utf8               str32
   #65 = Fieldref           #8.#66        // com/example/demo/lesson/jvm/construction/Master.strN4:Ljava/lang/String;
   #66 = NameAndType        #67:#47       // strN4:Ljava/lang/String;
   #67 = Utf8               strN4
   #68 = String             #69           // str35
   #69 = Utf8               str35
   #70 = Methodref          #53.#71       // java/lang/String.intern:()Ljava/lang/String;
   #71 = NameAndType        #72:#73       // intern:()Ljava/lang/String;
   #72 = Utf8               intern
   #73 = Utf8               ()Ljava/lang/String;
   #74 = Fieldref           #8.#75        // com/example/demo/lesson/jvm/construction/Master.strI2:Ljava/lang/String;
   #75 = NameAndType        #76:#47       // strI2:Ljava/lang/String;
   #76 = Utf8               strI2
   #77 = String             #78           // str37
   #78 = Utf8               str37
   #79 = Fieldref           #8.#80        // com/example/demo/lesson/jvm/construction/Master.strI4:Ljava/lang/String;
   #80 = NameAndType        #81:#47       // strI4:Ljava/lang/String;
   #81 = Utf8               strI4
   #82 = String             #83           // str54
   #83 = Utf8               str54
   #84 = String             #85           // str56
   #85 = Utf8               str56
   #86 = String             #87           // str57
   #87 = Utf8               str57
   #88 = String             #89           // str59
   #89 = Utf8               str59
   #90 = String             #91           // str60
   #91 = Utf8               str60
   #92 = Fieldref           #93.#94       // java/lang/System.out:Ljava/io/PrintStream;
   #93 = Class              #95           // java/lang/System
   #94 = NameAndType        #96:#97       // out:Ljava/io/PrintStream;
   #95 = Utf8               java/lang/System
   #96 = Utf8               out
   #97 = Utf8               Ljava/io/PrintStream;
   #98 = Fieldref           #8.#99        // com/example/demo/lesson/jvm/construction/Master.integerMin1:Ljava/lang/Integer;
   #99 = NameAndType        #100:#32      // integerMin1:Ljava/lang/Integer;
  #100 = Utf8               integerMin1
  #101 = Methodref          #102.#103     // java/io/PrintStream.println:(Z)V
  #102 = Class              #104          // java/io/PrintStream
  #103 = NameAndType        #105:#106     // println:(Z)V
  #104 = Utf8               java/io/PrintStream
  #105 = Utf8               println
  #106 = Utf8               (Z)V
  #107 = Fieldref           #8.#108       // com/example/demo/lesson/jvm/construction/Master.integerMax1:Ljava/lang/Integer;
  #108 = NameAndType        #109:#32      // integerMax1:Ljava/lang/Integer;
  #109 = Utf8               integerMax1
  #110 = Fieldref           #8.#111       // com/example/demo/lesson/jvm/construction/Master.strN1:Ljava/lang/String;
  #111 = NameAndType        #112:#47      // strN1:Ljava/lang/String;
  #112 = Utf8               strN1
  #113 = String             #114          // str29
  #114 = Utf8               str29
  #115 = String             #116          // abc
  #116 = Utf8               abc
  #117 = Fieldref           #8.#118       // com/example/demo/lesson/jvm/construction/Master.master1:Lcom/example/demo/lesson/jvm/construction/Master;
  #118 = NameAndType        #119:#12      // master1:Lcom/example/demo/lesson/jvm/construction/Master;
  #119 = Utf8               master1
  #120 = Fieldref           #8.#121       // com/example/demo/lesson/jvm/construction/Master.master3:Lcom/example/demo/lesson/jvm/construction/Master;
  #121 = NameAndType        #122:#12      // master3:Lcom/example/demo/lesson/jvm/construction/Master;
  #122 = Utf8               master3
  #123 = Fieldref           #8.#124       // com/example/demo/lesson/jvm/construction/Master.int3:I
  #124 = NameAndType        #125:#19      // int3:I
  #125 = Utf8               int3
  #126 = Fieldref           #8.#127       // com/example/demo/lesson/jvm/construction/Master.integerMax3:Ljava/lang/Integer;
  #127 = NameAndType        #128:#32      // integerMax3:Ljava/lang/Integer;
  #128 = Utf8               integerMax3
  #129 = Fieldref           #8.#130       // com/example/demo/lesson/jvm/construction/Master.integerMin3:Ljava/lang/Integer;
  #130 = NameAndType        #131:#32      // integerMin3:Ljava/lang/Integer;
  #131 = Utf8               integerMin3
  #132 = String             #133          // str26
  #133 = Utf8               str26
  #134 = Fieldref           #8.#135       // com/example/demo/lesson/jvm/construction/Master.str3:Ljava/lang/String;
  #135 = NameAndType        #136:#47      // str3:Ljava/lang/String;
  #136 = Utf8               str3
  #137 = String             #138          // str31
  #138 = Utf8               str31
  #139 = Fieldref           #8.#140       // com/example/demo/lesson/jvm/construction/Master.strN3:Ljava/lang/String;
  #140 = NameAndType        #141:#47      // strN3:Ljava/lang/String;
  #141 = Utf8               strN3
  #142 = String             #143          // str34
  #143 = Utf8               str34
  #144 = Fieldref           #8.#145       // com/example/demo/lesson/jvm/construction/Master.strI1:Ljava/lang/String;
  #145 = NameAndType        #146:#47      // strI1:Ljava/lang/String;
  #146 = Utf8               strI1
  #147 = String             #148          // str36
  #148 = Utf8               str36
  #149 = Fieldref           #8.#150       // com/example/demo/lesson/jvm/construction/Master.strI3:Ljava/lang/String;
  #150 = NameAndType        #151:#47      // strI3:Ljava/lang/String;
  #151 = Utf8               strI3
  #152 = Utf8               int1
  #153 = Utf8               ConstantValue
  #154 = Integer            9
  #155 = Integer            10
  #156 = Utf8               str1
  #157 = String             #158          // str24
  #158 = Utf8               str24
  #159 = Utf8               Code
  #160 = Utf8               LineNumberTable
  #161 = Utf8               main
  #162 = Utf8               ([Ljava/lang/String;)V
  #163 = Utf8               StackMapTable
  #164 = Class              #165          // "[Ljava/lang/String;"
  #165 = Utf8               [Ljava/lang/String;
  #166 = Utf8               <clinit>
  #167 = Utf8               SourceFile
  #168 = Utf8               Master.java

参考资料

《深入理解Java虚拟机》-周志明

posted @ 2020-09-05 18:18  Seal_lee  阅读(339)  评论(0编辑  收藏  举报