【深入浅出-JVM】(76):classloader

方法

  • public Class<?> loadClass(String name) throws ClassNotFoundException
    通过类名发挥这个类的Class实例
  • protected final Class<?> defineClass(byte[] b,int off,int len)
    根据给定的字节码流 b,off 和 len 参数表示实际的 class 信息在byte 数组中的位置和长度,其中 byte 数组 b是 classloader 从外部获取的
  • protected Class<?> findClass(String name)throws ClassNotFoundException
    查看一个类
  • protected final Class<?> findLoadedClass(String name)

    分类

  • BootStrap ClassLoader
  • Extension ClassLoader
  • AppClassLoader

    启动类加载器负责加载系统的核心类(rt.jar的java类),扩展类加载器加载 %JAVA_HOME/lib/ext/*.jar中的类,应用类加载器用于加载用户类 (classpath),自定义类加载器加载一些特殊路径的类(自定义classloader)

    双亲委托

  1. 当前 classloader 首先从自己已经加载的类中查询是否此类已经加载,如果已经加载了则直接返回原来已经加载的类
  2. 当前 classloader 的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查下自己的缓存,然后委托父类去加载,一直到 bootstrap classloader
  3. 当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入自己的缓存中,下次请求的时候直接返回
  4. 一直循环重复

作用

  • 各个类加载器的基础类统一

jar -cvf test.jar HelloLoader.class 把class打包成jar

Extension ClassLoader

例子:在 ext 路径下放一个自己 jar 包并加载

package com.mousycoder.server;

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

idea 通过 structs->artifacts->jar 然后 build-> build artifacts->build 生成 helloworld.jar
放到 /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/ext

package com.mousycoder.mycode.thinking_in_jvm;

import java.lang.reflect.Method;

/**
 * @version 1.0
 * @author: mousycoder
 * @date: 2019-09-06 10:35
 */
public class ExtClassLoader {

    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println(System.getProperty("java.ext.dirs"));
        Class<?> helloClass = Class.forName("com.mousycoder.server.HelloWorld");
        System.out.println(helloClass.getClassLoader());
    }
}

输出

/Users/mousycoder/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java
[email protected]

可以看出是 ExtClassLoader 加载 java.ext.dirs 目录

自定义类加载器

package com.mousycoder.mycode.thinking_in_jvm;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * @version 1.0
 * @author: mousycoder
 * @date: 2019-09-06 11:13
 */
public class MyClassLoader extends ClassLoader {

    private final static Path DEFAULT_CLASS_PATH = Paths.get("","/Users/mousycoder/My");

    private final Path classDir;

    public MyClassLoader(){
        super();
        this.classDir = DEFAULT_CLASS_PATH;

    }

    public MyClassLoader(String classDir){
        super();
        this.classDir = Paths.get(classDir);
    }

    public MyClassLoader(String classDir, ClassLoader parent){
        super(parent);
        this.classDir = Paths.get(classDir);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] classBytes = this.readClassBytes(name);

            if (null == classBytes || 0 == classBytes.length){
                throw new ClassNotFoundException("can not load the class" + name);
            }
            return this.defineClass(name,classBytes,0,classBytes.length);
        } catch (IOException e){
            e.printStackTrace();
        }
        return null;
    }

    private byte[] readClassBytes(String name) throws ClassNotFoundException, IOException {
        String classPath = name.replace(".","/");
        Path classFullPath = classDir.resolve( "HelloWorld1.class");
        if (!classFullPath.toFile().exists()){
            throw new ClassNotFoundException("The class" + name + "mpt found");
        }

        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()){
            Files.copy(classFullPath,baos);
            return baos.toByteArray();
        } catch (IOException e){
            throw new ClassNotFoundException("load the class " + name + "occur error",e);
        }

    }

    @Override
    public String toString() {
        return "My ClassLoader";
    }
}

package com.mousycoder.mycode.thinking_in_jvm;

/**
 * @version 1.0
 * @author: mousycoder
 * @date: 2019-09-06 11:34
 */
public class MyClassLoaderTest {

    public static void main(String[] args) throws ClassNotFoundException {
        MyClassLoader classLoader = new MyClassLoader();
        Class<?> class1 = classLoader.loadClass("com.mousycoder.mycode.thinking_in_jvm.HelloWorld1");
        System.out.println(class1.getClassLoader());
    }
}
package com.mousycoder.mycode.thinking_in_jvm;

/**
 * @version 1.0
 * @author: mousycoder
 * @date: 2019-09-06 11:46
 */
public class HelloWorld1 {
    public static void main(String[] args) {
        System.out.println("Hello world1 ");
    }
}

把helloword1变成class放到/Users/mousycoder/My目录下即可
输出 My ClassLoader 代表 自定义类加载器加载了该类

上下文类加载器

作用

打破双亲委托机制,让上层父类加载器可以使用子类的加载器加载对象,比如Spi中的接口类在系统加载器中,但是实现类在应用加载器中

Tomcat 类加载器

目的

  1. 保证每个应用的类库独立隔离(即使同限定名不同版本的)
  2. 保证相同类库相同版本的类库共享
  3. 保证容器自身的类库和程序独立

加载顺序

  1. bootstrap 引导类加载器
  2. system 系统类加载器
  3. 应用类加载器 WEB-INF/classes
  4. 应用类加载器 WEB-INF/lib
  5. common 类加载器 CATALINA/lib

原文地址:https://www.cnblogs.com/mousycoder/p/11528992.html

时间: 2024-10-17 20:40:01

【深入浅出-JVM】(76):classloader的相关文章

JVM的ClassLoader过程分析

本文来自网络:深入分析Java ClassLoader原理 http://my.oschina.net/zhengjian/blog/133836 一. JVM的ClassLoader过程以及装载原理 ClassLoader就是寻找类或是接口的字节码文件(.class)并通过解析字节码文件来构造类或接口对象的过程.在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:寻找文件.链接和初始化,其中链接又可以分成校验.准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个

JVM中classloader双亲委派

public class Test { public static void main(String[] args) { // TODO Auto-generated method stub ClassLoader cl = Test.class.getClassLoader(); while(cl!=null) { System.out.println(cl.getClass().getName()); cl = cl.getParent(); } System.out.println(cl)

深入浅出 JVM GC(3)

# 前言 在 深入浅出 JVM GC(2) 中,我们介绍了一些 GC 算法,GC 名词,同时也留下了一个问题,就是每个 GC 收集器的具体作用.有哪些 GC 收集器呢? Serial 串行收集器(只适用于堆内存 256M 以下的 JVM ) ParNew 并行收集器(Serial 收集器的多线程版本) Parallel Scavenge (PS 收集器,该收集器以吞吐量为主要目的,是1.8的默认 GC) CMS 收集器(该收集器全称 Concurrent Mark Sweep,是一种关注最短停顿

深入浅出 JVM GC(2)

# 前言 在 深入浅出 JVM GC(1) 中,限于上篇文章的篇幅,我们留下了一个问题 : 如何回收? 这篇文章将重点讲述这个问题. 在上篇文章中,我们也列出了一些大纲,今天我们就按照那个大纲来逐个讲解.在此,我将大纲复制过来. 垃圾回收算法 标记清除算法 复制算法 标记整理算法 分代收集算法(堆如何分代) 有哪些垃圾收集器 Serial 串行收集器(只适用于堆内存256m 以下的 JVM ) ParNew 并行收集器(Serial 收集器的多线程版本) Parallel Scavenge (P

JVM思考-ClassLoader.loadClasshe和Class.forName区别

JVM思考-ClassLoader.loadClasshe和Class.forName区别 目录:JVM总括:目录 见博客第四节:JVM总括四-类加载过程.双亲委派模型.对象实例化过程 原文地址:https://www.cnblogs.com/java-zzl/p/9905223.html

深入浅出 JVM ClassLoader

# 前言 在 JVM 综述里面,我们说,JVM 做了三件事情,Java 程序的内存管理, Java Class 二进制字节流的加载(ClassLoader),Java 程序的执行(执行引擎).我们也说,我们大部分情况下只关注前2个.在前面的文章中,我们已经分析了内存关系相关的,包括运行时数据区,GC 相关.今天我们要讲的就是类加载器. 在 JVM 综述 里,我们已经大致分析了一些概念.而今天的文章将详细的阐述类加载器. 首先,我们要了解类加载器,当然,了解的目的是为了更好的开发,通过对类加载器的

关于JVM的ClassLoader(转)

众所周知,java是编译型的语言,写的是java文件,最后运行的是class文件,class文件是运行在JVM之中的,这时候就有一个问题,JVM如何装载class文件的?是通过ClassLoader来进行的,这里做一下笔记,因为发现原作者写的很好<深入分析java web 技术内幕>. ClassLoader的结构分析 ClassLoader是一个抽象类,他有很多子类,JVM默认有几个实现类,当然我们也可以自己继承ClassLoader. 1.defineClass:将byte字节转换为JVM

JVM的classloader(转)

Java中一共有四个类加载器,之所以叫类加载器,是程序要用到某个类的时候,要用类加载器载入内存.    这四个类加载器分别为:Bootstrap ClassLoader.Extension ClassLoader.AppClassLoader和URLClassLoader,他们的作用其实从名字就可以大概推测出来了.其中AppClassLoader在很多地方被叫做System ClassLoaderBootstrap ClassLoader是在JVM开始运行的时候加载java的核心类,是用C++编

java虚拟机学习-慢慢琢磨JVM(2-1)ClassLoader的工作机制

ClassLoader的工作机制 java应用环境中不同的class分别由不同的ClassLoader负责加载. 一个jvm中默认的classloader有Bootstrap ClassLoader.Extension ClassLoader.App ClassLoader,分别各司其职: Bootstrap ClassLoader     负责加载java基础类,主要是 %JRE_HOME/lib/ 目录下的rt.jar.resources.jar.charsets.jar和class等 Ex