意义

类加载器是一个运行时核心基础设施模块,主要在启动之初进行累的Load,Link和Init,即加载、连接、初始化

Load

第一步, load阶段读取类文件产生二进制流, 并转化为特定的数据结构,初步校验cafe babe魔法数、常量池、文件长度等,即加载、链接、初始化。

Link

第二步, Link阶段包括验证、准备、解析三个步骤。

  • 验证阶段是更详细的校验,比如final是否合规、类型是否正确、静态变量是否合理等;
  • 准备阶段是为静态变量分配内存,并设定默认值。
  • 解析阶段是解析类和方法确保类与类之间相互的引用正确性,完成内存的结构布局

Init

第三步, Init阶段执行类的够着器<clinit> 方法, 如果赋值运算通过其他类的静态方法来完成,那么会马上解析另外一个类,

在虚拟机栈中执行完毕后通过返回值进行赋值

flink on yarn jar加载_开发语言

等级制度

类加载器类似于原始部落接口,存在权利等级制度,单并非继承关系,以组合的关系来复用附加在器功能,通称双亲委派模型

最高一层

C/C++实现的,并不存在JVM体系内。

Bootstarp是类加载器家族中最有威望的。

是在JVM启动时创建的,通常由与操作系统相关的本地代码实现,是最根基的类加载器。

负者装载最核心的java类,比如Object, System, String等。

第二层

Java实现的

在JDK9版本中称为Platform ClassLoader 既平台加载类。

用于加载一些扩展的系统类, 比如XML、加密、压缩相关的功能类

JDK9之前的加载器为Extension ClassLoader;

第三层

Java实现的

应用加载类(Application ClassLoader)。

加载用户定义的CLASSPATH路径下的类。

总结

flink on yarn jar加载_开发语言_02

查看类加载器等级制度代码

ClassLoader c = TestDebugInfo.class.getClassLoader ();
 System.out.println (c);
 ClassLoader c1 = c.getParent ();
 System.out.println (c1);
 ClassLoader c2 = c1.getParent ();
 System.out.println (c2);

* 低层级的加载器不可覆盖高层级的加载器

查看Bootstrap所有已加载的类库代码

//查询 Bootstrap所有加载的类库
        URL[] urls = Launcher.getBootstrapClassPath ().getURLs ();
        for(URL url :  urls){
            System.out.println (url.toExternalForm ());
        }

追加Boorstrap架子路径: 在JVM启动命令 -Xbootclasspath/User/....

启动时观察加载了哪些jar包中的哪些类,启动时增加: -XX:+TraceClass:Loading

自定义加载类

自定义加载类的几种原因

隔离加载类

进行中间件玉应用的模块的隔离,把类加载到不同的环境。

修改类的加载方式

类的加载模型不是固定的,除Bootstrap外,其他的加载并非一定引入,可以根据实际的情况在某个时间点进行按需进行动态加载

扩展加载源

比如从数据库,网络,或者是电视机机顶盒进行加载

防止源码泄露

对java代码进行编译加密,然后类加载器重新定义,还原加密的字节码

自定义加载器代码

public class CustomClassLoader extends ClassLoader{
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException{
        try {
            byte[] result = getClassFromCustomPath(name);
            if(Objects.isNull (result)){
                throw new FileNotFoundException ();
            }else {
                return defineClass (name, result, 0, result.length);
            }

        }catch (Exception e){
            e.printStackTrace ();
        }

        throw new ClassNotFoundException (name);
    }

    private byte[] getClassFromCustomPath(String name) {
        //从自定义路径中加载指定类
        String myPath = "file:///Users/sheep/Desktop/" + name.replace(".","/") + ".class";
        System.out.println(myPath);
        byte[] cLassBytes = null;
        Path path = null;
        try {
            path = Paths.get(new URI (myPath));
            cLassBytes = Files.readAllBytes(path);
        } catch (IOException | URISyntaxException e) {
            e.printStackTrace();
        }

        return cLassBytes;
    }

    public static void main(String[] args) {
        CustomClassLoader customClassLoader = new CustomClassLoader ();
        try{
            Class<?> clazz = Class.forName ("Test", true, customClassLoader);
            Object obj = clazz.newInstance ();
            System.out.println (obj.getClass ().getClassLoader ());

        } catch (Exception e) {
            e.printStackTrace ();
        }
    }
}

以上内容摘抄至《Easy Coding》

后续拜读了这篇文档,觉得解释很不错记录一下