美文网首页
Java类加载器

Java类加载器

作者: 币来币往 | 来源:发表于2019-03-05 17:05 被阅读0次

Java加载类的方式有两种:

  1. 通过BootstrapClassLoader 加载,该类是由c++代码实现的,加载lib下面的jar;
  2. 通过继承ClassLoader来加载类。
  • ExtClassLoader, 负责加载java.ext.dirs下面的jar
  • AppClassLoader, 负责加载classpath路径下的jar
  • 用户自定义的classLoader

java类加载机制采用双亲委托模式,即发现需要加载的类之后先由父类加载,如果父类加载不了再由自己加载。为什么需要双亲委派模型呢?假设没有双亲委派模型,试想一个场景:

黑客自定义一个java.lang.String类,该String类具有系统的String类一样的功能,只是在某个函数稍作修改。比如equals函数,这个函数经常使用,如果在这这个函数中,黑客加入一些“病毒代码”。并且通过自定义类加载器加入到JVM中。此时,如果没有双亲委派模型,那么JVM就可能误以为黑客自定义的java.lang.String类是系统的String类,导致“病毒代码”被执行。

而有了双亲委派模型,黑客自定义的java.lang.String类永远都不会被加载进内存。因为首先是最顶端的类加载器加载系统的java.lang.String类,最终自定义的类加载器无法加载java.lang.String类。

或许你会想,我在自定义的类加载器里面强制加载自定义的java.lang.String类,不去通过调用父加载器不就好了吗?确实,这样是可行。但是,在JVM中,判断一个对象是否是某个类型时,如果该对象的实际类型与待比较的类型的类加载器不同,那么会返回false。

举个简单例子:

ClassLoader1、ClassLoader2都加载java.lang.String类,对应Class1、Class2对象。那么Class1对象不属于ClassLoad2对象加载的java.lang.String类型。

下面我们自己实现一个classLoader

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Method;

public class MyClassLoader extends ClassLoader {
    private String classPath;

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

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] data = loadByte(name);
            return defineClass(name, data, 0, data.length);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ClassNotFoundException();
        }
    }

    private byte[] loadByte(String name) throws Exception {
        System.out.println(classPath + File.separator + name + ".class");
        FileInputStream fis = new FileInputStream(classPath + File.separator + name + ".class");
        int length = fis.available();
        byte[] data = new byte[length];
        fis.read(data);
        fis.close();
        return data;
    }

    public static void main(String[] args) throws Exception {
        ClassLoader classLoader = new MyClassLoader("D:\\t");
        Class<?> test = classLoader.loadClass("Test");
        Object o = test.newInstance();
        Method hello = test.getDeclaredMethod("hello", null);
        hello.invoke(o, null);

    }
}

只需要覆盖findClass即可。

相关文章

网友评论

      本文标题:Java类加载器

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