类加载器窥探

.java文件 编译后,得到.class文件,JVM 需要 读取这些.class文件才能后运行。

那么,如何读取.class文件呢?这就是 类加载器需要解决的问题。

JDK提供的:java.lang.ClassLoader  是一个抽象类

实现ClassLoader的子类,以扩展Java虚拟机动态加载类的方式

ClassLoader类使用委托模型来搜索类和资源:

        类加载器的每个实例都有一个关联的父类加载器。

        当请求查找类或资源时,类加载器实例将在尝试查找类或资源本身之前,将对该类或资源的搜索委托给其父类加载器。

虚拟机的内置类加载器称为“引导类加载器”,它本身没有父类,但可以作为类加载器实例的父类。

Java虚拟机以依赖于平台的方式从本地文件系统加载类。例如,在UNIX系统上,虚拟机从CLASSPATH环境变量定义的目录加载类。但是,有些类可能不是源于文件;它们可能来自其他来源,如网络,也可能由应用程序构建

defineClass方法将字节数组转换为类的实例

为了确定引用的类,Java虚拟机调用最初创建该类的类加载器的loadClass方法。

class NetworkClassLoader extends ClassLoader {
           String host;
           int port;
  
           public Class findClass(String name) {
               byte[] b = loadClassData(name);
               return defineClass(name, b, 0, b.length);
           }
  
           private byte[] loadClassData(String name) {
               // load the class data from the connection
                . . .
           }
       }

// 父类加载器

private final ClassLoader parent;
public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }
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();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                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
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

 // 类加载器,必须实现该方法
 protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }

 protected final Class<?> defineClass(String name, byte[] b, int off, int len)
        throws ClassFormatError
    {
        return defineClass(name, b, off, len, null);
    }

示例,


public class MyClassLoader extends ClassLoader{


    public static void main(String[] args) throws Exception{

        Thread mc = new Thread(() -> {
            People people = new People();
            // People,这样是用 sun.misc.Launcher$AppClassLoader@18b4aac2 加载
            System.out.printf("people getClassLoader "+people.getClass().getClassLoader());

            try {
                // 获取当前线程的 类加载器
                ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
                Class<?> peopleClass = Class.forName("wxj.test.mclassloader.People", true, classLoader);
                // peopleClass getClassLoader wxj.test.mclassloader.MyClassLoader@65fc50e4
                System.out.printf("peopleClass getClassLoader " + peopleClass.getClassLoader());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

        }, "mc");
        // 设置当前线程的 类加载器
        mc.setContextClassLoader(new MyClassLoader());
        mc.start();

        while (true){}
    }

    public MyClassLoader(ClassLoader parent) {
        super(parent);
    }

    public MyClassLoader() {
    }

    /**
     * 类加载器的 入口
     * 如果自定义类加载器,重写了 改方法,那么 就会走自己定义的 加载规则
     */
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        System.out.println("MyClassLoader.loadClass:exe...");
        return super.loadClass(name);
    }

    /**
     *  如果自定义类加载器重写了  loadClass 方法,那么 可以 实现 findClass,也可以不实现,因为 加载规则是自己定义的
     *  如果自定义类加载器没有重新 loadClass方法,根据双亲委派,父类加载器加载失败时,会调用 findClass 加载
     */
    protected Class<?> findClass(String name) throws ClassNotFoundException
    {
        System.out.println("MyClassLoader.findClass:exe...");
        String classPath = "D:\\wxjwork\\code\\testv0\\cal\\target\\classes\\wxj\\test\\mclassloader";
        File file = new File(classPath + "\\People.class");
        try{
            byte[] bytes = getClassBytes(file);

            //defineClass方法可以把二进制流字节组成的文件转换为一个java.lang.Class
            Class<?> c = this.defineClass(name, bytes, 0, bytes.length);
            return c;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    private byte[] getClassBytes(File file) throws Exception
    {
        // 这里要读入.class的字节,因此要使用字节流
        FileInputStream fis = new FileInputStream(file);
        FileChannel fc = fis.getChannel();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        WritableByteChannel wbc = Channels.newChannel(baos);
        ByteBuffer by = ByteBuffer.allocate(1024);

        while (true){
            int i = fc.read(by);
            if (i == 0 || i == -1)
                break;
            by.flip();
            wbc.write(by);
            by.clear();
        }
        fis.close();
        return baos.toByteArray();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值