自定义类加载器(破坏双亲委派模型)

写这个自定义类加载器是因为了解到热部署的原理,是通过打破了双亲委派模型的自定义类加载器来加载的,使用新的类加载器实例来加载新的类,然后替换掉方法区中的旧的类。

两个类,一个KaJong类,一个MyClassLoader类。直接调用findClass()方法是为了打破双亲委派模型,如果直接调用loadClass()方法,尽管loadClass()方法里面调用了findClass()方法,但这样加载出来的类并没有打破双亲委派模型。(因为loadClass方法进行了双亲委派的逻辑处理,优先将类交给父类进行加载)

public class KaJong {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//        使用这个方法获取到的路径有问题,因为我的目录中包含有空格,可能是字符处理上有问题
//        URL url = MyClassLoader.getSystemResource("KaJong.class");
//        String file = url.getPath();
        String file = System.getProperty("user.dir")+"\\target\\classes\\com\\example\\demo\\classloadertest\\KaJong.class";
        System.out.println(file);
        //通过自定义类加载器1加载的类对象
        MyClassLoader myClassLoader1 = new MyClassLoader(file);
        Class kajong1 = myClassLoader1.findClass("com.example.demo.classloadertest.KaJong");
        //通过系统类加载器加载的类对象
        Class kajong2 = KaJong.class;
        //通过自定义类加载器2加载的类对象
        MyClassLoader myClassLoader2 = new MyClassLoader(file);
        Class kajong3 = myClassLoader2.findClass("com.example.demo.classloadertest.KaJong");
        System.out.println(kajong1.toString());
        System.out.println(kajong2.toString());
        System.out.println(kajong1.equals(kajong2));
        System.out.println(kajong1.equals(kajong3));
        System.out.println("kajong1's classloader:"+kajong1.getClassLoader().toString());
        System.out.println("kajong2's classloader:"+kajong2.getClassLoader().toString());
        System.out.println("kajong3's classloader:"+kajong3.getClassLoader().toString());
    }
}

MyClassLoader类需要继承ClassLoader方法,重写findClass方法,通过调用defineClass方法来加载二进制字节码文件。注意这里的new byte[fi.available()]是必需的,哪怕只多一个空字节都会报错,使用fi.available()可以获取到文件流的字节长度。

public class MyClassLoader extends ClassLoader {
    private String file;

    public MyClassLoader(String file){
        this.file = file;
    }

    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] b = null;
        byte[] a = null;
        try {
//            绝对路径
//            File file = new File("com.example.demo.create.KaJong");
//            InputStream fi = new FileInputStream(new File("C:\\Users\\good luck\\Desktop\\learnJavaItem\\target\\classes\\com\\example\\demo\\classloadertest\\KaJong.class"));
            InputStream fi = new FileInputStream(new File(file));
//            System.out.println(fi.available());
            a = new byte[fi.available()];
            fi.read(a);
            fi.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
//        System.out.println("name= " + name);
        Class kaJong = defineClass(name,a,0,a.length);
//        System.out.println(kaJong.toString());
        return kaJong;
    }
}

下面是输出结果,可以看到不同的类加载器加载的KaJong类,使用equals方法判断的结果也不相等。 

C:\Users\good luck\Desktop\learnJavaItem\target\classes\com\example\demo\classloadertest\KaJong.class
class com.example.demo.classloadertest.KaJong
class com.example.demo.classloadertest.KaJong
false
false
kajong1's classloader:com.example.demo.classloadertest.MyClassLoader@7ba4f24f
kajong2's classloader:sun.misc.Launcher$AppClassLoader@18b4aac2
kajong3's classloader:com.example.demo.classloadertest.MyClassLoader@7699a589

 

引用:

1.浅谈Java 中文件的读取File、以及相对路径的问题http://www.luyixian.cn/java_show_182845.aspx

2.深入解析Java绝对路径与相对路径https://www.jianshu.com/p/982d8759edde

3.Java 类加载与自定义类加载器详解https://www.jb51.net/article/103745.htm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值