代码编织梦想

目录

1. 类加载机制

2. 双亲委派机制

3. Springboot内嵌Tomcat工作原理

3.1 findClass

3.2 loadClass

3.3 总结


1. 类加载机制

1) 启动类加载器:由C++实现,负责加载JAVA_HOME\lib目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类。

2) 扩展类加载器:负责加载JAVA_HOME\lib\ext目录中的,或通过java.ext.dirs系统变量指定路径中的类库。

3) 应用程序类加载器:负责加载用户路径(classpath)上的类库。

4) 自定义类加载器:通过继承java.lang.ClassLoader实现自定义的类加载器。

2. 双亲委派机制

各个类加载器之间是组合关系,并非继承关系。

当一个类加载器收到类加载的请求,它将这个加载请求委派给父类加载器进行加载,每一层加载器都是如此,最终,所有的请求都会传送到启动类加载器中。只有当父类加载器自己无法完成加载请求时,子类加载器才会尝试自己加载。

  • 双亲委派模型可以确保安全性,可以保证所有的Java类库都是由启动类加载器加载。
  • 防止内存中存在多份同样的字节码。

如用户编写的java.lang.Object,加载请求传递到启动类加载器,启动类加载的是系统中的Object对象,而用户编写的java.lang.Object不会被加载。

如用户编写的java.lang.virus类,加载请求传递到启动类加载器,启动类加载器发现virus类并不是核心Java类,无法进行加载,将会由具体的子类加载器进行加载,而经过不同加载器进行加载的类是无法访问彼此的,所有的访问权限都是基于同一个运行时包而言的。

3. Springboot内嵌Tomcat工作原理

一个 Tomcat 可能会部署多个这样的 web 应用,不同的 web 应用可能会依赖同一个第三方库的不同版本,为了保证每个 web 应用的类库都是独立的,需要实现类隔离。而Tomcat 的自定义类加载器 WebAppClassLoader 解决了这个问题。

每一个 web 应用都会对应一个 WebAppClassLoader 实例,不同的类加载器实例加载的类是不同的,Web应用之间通各自的类加载器相互隔离。

3.1 findClass

@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
    // Ask our superclass to locate this class, if possible
    // (throws ClassNotFoundException if it is not found)
    Class<?> clazz = null;

    // 先在自己的 Web 应用目录下查找 class
    clazz = findClassInternal(name);

    // 找不到 在交由父类来处理
    if ((clazz == null) && hasExternalRepositories) {  
        clazz = super.findClass(name);
    }
    if (clazz == null) {
         throw new ClassNotFoundException(name);
    }
    return clazz;
}

对于 Tomcat 的类加载的 findClass 方法:

  • 首先在 web 目录下查找。
  • 找不到再交由父类的 findClass 来处理。
  • 都找不到就抛出 ClassNotFoundException。 

3.2 loadClass

public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    synchronized (getClassLoadingLock(name)) {
        Class<?> clazz = null;
        //1. 先在本地cache查找该类是否已经加载过
        clazz = findLoadedClass0(name);
        if (clazz != null) {
            if (resolve)
                resolveClass(clazz);
            return clazz;
        }
        //2. 从系统类加载器的cache中查找是否加载过
        clazz = findLoadedClass(name);
        if (clazz != null) {
            if (resolve)
                resolveClass(clazz);
            return clazz;
        }
       // 3. 尝试用ExtClassLoader类加载器类加载
        ClassLoader javaseLoader = getJavaseClassLoader();
        try {
            clazz = javaseLoader.loadClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return clazz;
            }
        } catch (ClassNotFoundException e) {
            // Ignore
        }
        // 4. 尝试在本地目录搜索class并加载
        try {
            clazz = findClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return clazz;
            }
        } catch (ClassNotFoundException e) {
            // Ignore
        }
        // 5. 尝试用系统类加载器(也就是AppClassLoader)来加载
            try {
                clazz = Class.forName(name, false, parent);
                if (clazz != null) {
                    if (resolve)
                        resolveClass(clazz);
                    return clazz;
                }
            } catch (ClassNotFoundException e) {
                // Ignore
            }
       }
    //6. 上述过程都加载失败,抛出异常
    throw new ClassNotFoundException(name);
}

加载步骤:

  • 先在本地cache查找该类是否已经加载过,看看 Tomcat 有没有加载过这个类。
  • 如果Tomcat 没有加载过这个类,则从系统类加载器的cache中查找是否加载过。
  • 如果没有加载过这个类,尝试用ExtClassLoader类加载器类加载。重点来了,这里并没有首先使用 AppClassLoader 来加载类,这个Tomcat 的 WebAPPClassLoader 违背了双亲委派机制,直接使用了 ExtClassLoader来加载类。这里注意 ExtClassLoader 双亲委派依然有效,ExtClassLoader 就会使用 Bootstrap ClassLoader 来对类进行加载,保证了 Jre 里面的核心类不会被重复加载。 比如在 Web 中加载一个 Object 类,WebAppClassLoader → ExtClassLoader → Bootstrap ClassLoader这个加载链,就保证了 Object 不会被重复加载。
  • 如果 BoostrapClassLoader,没有加载成功,就会调用自己的 findClass 方法由自己来对类进行加载,findClass 加载类的地址是自己本 web 应用下的 class。
  • 加载依然失败,才使用 AppClassLoader 继续加载。
  • 都没有加载成功的话,抛出异常。

3.3 总结

WebAppClassLoader 加载类的时候,故意打破了JVM 双亲委派机制,绕开了 AppClassLoader,直接使用 ExtClassLoader 来加载类。

  • 保证了基础类不会被同时加载。
  • 也保证了在同一个 Tomcat 下不同 web 之间的 class 是相互隔离的。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/BAStriver/article/details/129817154

关于gzipoutputstream的一些使用总结-爱代码爱编程

1. 首先,网上很多教程有写怎么使用java内置的gzip工具类,这里就不多少了,主要是想说一下,当我们压缩生成gz文件的时候,如果要保留原始文件的后缀,比如a.xml压缩成a.xml.gz 那么,我们在生成压缩包指定文件名的时候把这个.xml加上。 Gzip工具类: package com.util; import java.io.*; impor

20191210双亲委派模型,类的加载机制,搞定大厂高频面试题-爱代码爱编程

文章内容相对较长,所以添加了目录,如果你希望对 Java 的类加载过程有个更深入的了解,同时增加自己的面试技能点,请耐心读完...... 双亲委派模型 在介绍这个Java技术点之前,先试着思考以下几个问题: 为什么我们不能定义同名的 String 的 java 文件?多线程的情况下,类的加载为什么不会出现重复加载的情况?热部署的原理是什么?下面代码,

AWS S3文件/文件夹删除-爱代码爱编程

1. 关于AWS S3的使用相关知识总结可以参考:AWS S3 学习小结。 2. 以下主要是想总结一下关于S3文件、文件夹如何删除,示例版本是源码里面的java2。 注:要知道,S3不存在子文件夹的概念,而是所有文件都在根目录。 假设有/home/files/如下的文件结构: 并且,有这样一个工具类。 package com.bas.util

聊聊类加载器与双亲委派模型-爱代码爱编程

前言 我们经常会在面试中遇到有关类加载器的问题,而作为一名Java开发人员应该了解类加载器如何工作?双亲委派模型是什么?如何打破双亲委派?为什么打破?等等。所以今天的主题就是聊一聊类加载器。 ClassLoader 介绍 《深入理解Java虚拟机》这本书大家都不陌生,想必我们大多数人了解JVM知识都是通过这本书,在该书中也详细介绍了Java类加载的全

面试刷题23:类加载过程和双亲委派机制?-爱代码爱编程

jvm赋能java跨平台的能力,而类加载机制是深入理解java的必要条件。 我是李福春,我在准备面试,今天的问题是: java的类加载机制是怎样的?什么是双亲委派原则? 答:java的类加载过程分为 加载,链接,初始化。 加载:即从数据源(jar,class,网络)加载class文件到jvm,映射为class对象,如果不是classFile结构,抛出C

Java类加载器、双亲委派机制及作用、加载不到类所报异常ClassNotFoundException-爱代码爱编程

文章目录 一、类加载器(Class Loader)二、双亲委派机制的意义三、如何破坏双亲委派四、一个异常、一个错误 一、类加载器(Class Loader) 1、类加载器的分类: ① 启动类加载器(根加载器)(BootstrapClassLoader); ② 扩展类加载器(ExtClassLoader); ③ 应用程序类加载器(系统类加载器

Java的类加载过程与双亲委派模型-爱代码爱编程

类加载 Java的类加载过程中涉及到双亲委派模型,而提到双亲委派模型又免不了讨论类的加载过程,既然这样的话,干脆就把这两者放一块吧。 目录如下,可根据自己需要自行食用。 目录 类加载加载阶段连接阶段验证阶段准备阶段解析阶段初始化阶段小结类加载器与双亲委派机制类加载器启动类加载器:Bootstrap ClassLoader扩展类加载器:Extens

JVM类加载过程与双亲委派机制与类加载器与类字节码详解-爱代码爱编程

JVM类加载过程与双亲委派机制与类加载器与类字节码详解 目录概 述配置文件.链接类加载器:类加载机制:相关工具如下:分析:小结:参考资料和推荐阅读 LD is tigger forever,CG are not brothers forever, throw the pot and shine forever. Modesty is no

Tomcat 的类加载机制-爱代码爱编程

        在前面 Java虚拟机:对象创建过程与类加载机制、双亲委派模型 文章中,我们介绍了 JVM 的类加载机制以及双亲委派模型,双亲委派模型的类加载过程主要分为以下几个步骤: (1)初始化 ClassLoader 时需要指定自己的 parent 是谁(2)先检查类是否已经被加载过,如果类已经被加载了,直接返回(3)若没有加载则调用父加载器 pa

jvm快速入门(二)——类加载器及双亲委派机制_jagtom的博客-爱代码爱编程

参考文章:  ​​​​​​​​​​​​​​​​​​​​​​​​​​​​JVM(二)- 类的加载过程、类加载器(付示例代码)_小狐狸Rosie的博客-CSDN博客 深入理解反射-类加载机制初识_JagTom的博客-CSDN博客 前景提要 如果 JVM 想要执行这个 .class 文件,我们需要将其装进一个类加载器 中,它就像一个搬运工一样,会把所

(jvm)双亲委派机制_其然乐衣的博客-爱代码爱编程

Java 虚拟机对 class 文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的 class 文件加载到内存生成 class 对象。而且加载某个类的 class 文件时,Java 虚拟机采用的是双亲委派模式,即把请求交由父类处理,它是一种任务委派模式。 工作原理 1)如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求

java双亲委派机制,类加载器详解_ocean&21的博客-爱代码爱编程

关于java语言类加载器以及双亲委托机制 一、类加载器概述二、类加载器的分类三、双亲委托机制(类加载过程)四、双亲委托机制的作用五、小结 一、类加载器概述 顾名思义,类加载器就是用来加载类到内存当中的一种工具

关于springboot的@service注入的方式_注入service-爱代码爱编程

1. 最近在写代码过程中发现Service注入的方式原来有这么多种的,所以记录一下这些方式。 2. 最常用的就是这种直接用@AutoWire的方式了: @Service public class TestServiceImp implements TestService { // } @RestController public class