Tomcat-聊聊ClassLoader的那些事儿

简介: Tomcat-聊聊ClassLoader的那些事儿

一、聊聊ClassLoader的那些事儿


  我们要分析清楚Tomcat中的类加载器相关的内容之前我们还是需要把JVM中的类加


载器给大家理清楚。



1.类加载器的过程


  类加载器的作用就是从文件系统或者网络中加载Class文件,至于他是否可以运行就不是ClassLoader的工作了。


image.png



2.类加载器的分类


  JVM中支持的类加载器有两种类型,分别是 引导类加载器【Bootstrap ClassLoader】和 自定义类加载器【User-Defined ClassLoader】


image.png

  在Java虚拟机层面定义:所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器。


image.png

可以通过源码看到对应的类加载器的继承关系


ExtClassLoader

image.png


AppClassLoader

image.png

通过具体的案例代码可以来看看类加载器的使用


public static void main(String[] args) {
        // 获取系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println("systemClassLoader = " + systemClassLoader);
        // 获取父类加载器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println("parent = " + parent);
        // 继续获取上层的类加载器
        ClassLoader bootstrapClassLoader = parent.getParent();
        System.out.println("bootstrapClassLoader = " + bootstrapClassLoader);
        // 自定义Java类
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println("classLoader = " + classLoader);
        // Java系统类
        ClassLoader classLoader1 = String.class.getClassLoader();
        System.out.println("classLoader1 = " + classLoader1);
    }
复制代码


对应的输出结果


systemClassLoader = sun.misc.Launcher$AppClassLoader@18b4aac2
parent = sun.misc.Launcher$ExtClassLoader@61bbe9ba
bootstrapClassLoader = null
classLoader = sun.misc.Launcher$AppClassLoader@18b4aac2
classLoader1 = null
复制代码




3.Bootstrap ClassLoader


  虚拟机自带的类加载器,启动类加载器


  • 通过C/C++实现的,JVM内置类加载器


  • 作用是用来加载Java的核心库(JAVA_HOME/jre/lib.rt.jar、resources.jar或者sun.boot.class.path路径下的内容)、用于提供JVM自身需要的类。


  • 没有继承java.lang.ClassLoader、没有父加载器,自己就是祖先了。


  • 加载扩展类和应用程序类加载器,并指定为他们的父类加载器


  • 出于安全考虑,Bootstrap启动类加载器只加载报名为java,javax,sun等开头的类

通过代码来看看具体的加载路径有哪些




public static void main(String[] args) {
        System.out.println("**************启动类加载器*************");
        URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
        for (int i = 0 ; i < urLs.length ; i ++){
            URL urL = urLs[i];
            System.out.println("urL = " + urL.toExternalForm());
        }
    }
复制代码




输出结果:

**************启动类加载器*************
urL = file:/D:/software/java/jdk8/jre/lib/resources.jar
urL = file:/D:/software/java/jdk8/jre/lib/rt.jar
urL = file:/D:/software/java/jdk8/jre/lib/sunrsasign.jar
urL = file:/D:/software/java/jdk8/jre/lib/jsse.jar
urL = file:/D:/software/java/jdk8/jre/lib/jce.jar
urL = file:/D:/software/java/jdk8/jre/lib/charsets.jar
urL = file:/D:/software/java/jdk8/jre/lib/jfr.jar
urL = file:/D:/software/java/jdk8/jre/classes
复制代码





4.Extension ClassLoader


  虚拟机自带的加载器。扩展类加载器,Java语音编写,是sun.misc.Launcher的内部类

image.png


派生于ClassLoader所以是自定义类加载器


image.png

父类加载器是BootstrapClassLoader。


image.png

  扩展类加载器是从扩展目录 java.ext.dirs系统属性指定的目录中加载类库,或者从JDK的安装目录的 jre/lib/ext子目录下加载雷凯,如果用户创建的jar包也放在了这个目录下,那么该类加载器也会自动加载的。


然后通过案例来看看扩展类加载器加载的路径


public static void main(String[] args) {
        System.out.println("**************扩展类加载器*************");
        String extDirs = System.getProperty("java.ext.dirs");
        System.out.println("extDirs = " + extDirs);
    }
复制代码



对应的输出结果

**************扩展类加载器*************
extDirs = D:\software\java\jdk8\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext
复制代码



然后通过加载路径下的Java类测试也能证明


image.png



5.App ClassLoader


  虚拟机自带的加载器,APPClassLoader也叫应用程序类加载器。Java语音编写,由sun.misc.Launcher下的内部类提供。也是派生于ClassLoader。


image.png

父类加载器为ExtClassLoader


image.png

  主要负责加载环境变量classpath或系统属性 java.class.path 指定路径下的类库,该类加载器是程序中的默认类加载器,一般来说,Java应用的类都是由它来完成加载的。通过 ClassLoader#getSystemClassLoader() 方法可以获取到该类加载器。




6.自定义类加载器


  在我们的日常应用程序的开发中,我基本是用不到自定义类加载器的,基本就是由前面介绍的这三个类加载器来相互配合搞定的。但是在有些特殊的情况下我们不希望通过系统的类加载器来处理,这时我们就可以通过自定义类加载来实现了。


  用户自定义类加载器的实现步骤:


  1. 我们可以直接编写 java.lang.ClassLoader 类的实现来完成自定义的处理


  1. 在JDK1.2之前,自定义类加载器时我们总是会继承ClassLoader然后重写loadClass方法,达到自定义类加载的目的,但是在JDK1.2之后建议把自定义的类加载逻辑放在findClass()方法中


  1. 最后在编写自定义类加载的时候,如果没有太过于复杂的需求,可以直接继承URLClassLoader类,这样可以达到简化自定义类加载器的目的





7.双亲委派机制


Java虚拟机对class文件采用的是 按需加载的方式,也就是当需要使用该类时才会将他的class文件加载到内存中生成class对象,而且加载某个类的class文件时,Java虚拟机采用的而是双亲委派模式。即把请求交由父类加载器处理,它是一种任务委派模式。



image.png


双亲委派的工作原理:


  1. 如果一个类加载器收到了类加载的请求,它并不会自己先去加载,而且把这个请求委托给父类的加载器去执行。


  1. 如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归请求,最终将请求流转到顶层的启动类加载器


  1. 如果父类加载器可以完成类加载任务,就成功返回,如果父类无法完成任务,子加载器才会尝试自己去加载。


举个简单的例子,我们自定义一个java.lang.String类,然后添加对应的main方式执行。



public class String {
    public static void main(String[] args) {
        System.out.println("自定义String类");
    }
}
复制代码

报错信息为:

image.png

原因就是双亲委派机制通过BootstrapClassLoader加载的是java包下的String,而不会加载我们自定义的。


双亲委派机制的有点:


  1. 避免类的重复加载


  1. 保护程序的安全,防止核心API被随意的篡改




相关文章
|
Java 应用服务中间件 缓存
Tomcat&#160;ClassLoader机制介绍
本文旨在介绍JVM的类加载机制;同时分析Tomcat不能采用默认的加载机制的原因,并对其加载机制做了介绍。 1、JVM中的类加载机制 在Java2之后的版本中,类的加载采用的是一种称为双亲委派的代理模型:也就是说当前ClassLoader在加载类前,先委派给双亲去加载类; 在有双亲委派模式的情况下,启动类装载器可以抢在标准扩展类装载器之前去装载类,而标准扩展类装载器可以抢在系统类装载器之前去装载那个类,类路径类装载器又可以抢在用户自定义类装载器之前去装载它,用这种方法,类装载器的体系结构就可以防止不可靠的代码用它们自己的版本来替代可信任的类。
1024 0
|
2月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
541 5
|
5月前
|
Java 应用服务中间件 Linux
在Java 12环境中配置和部署Apache Tomcat的步骤。
这段部署Tomcat的冒险旅程充满技术挑战,但同时也像游戏一样充满乐趣。它需要你提前准备,仔细执行,并随时准备解决意外情况。成功后,你就可以在这匹强壮的网络野马上,带着你的Java应用,冲向Web开发的璀璨星空。
204 56
|
8月前
|
网络协议 Java 应用服务中间件
框架源码私享笔记(01)Tomcat核心架构功能 | 配置详解
本文首先分享了《活出意义来》一书序言中的感悟,强调成功如同幸福,不是刻意追求就能得到,而是全心投入时的副产品。接着探讨了Tomcat的核心功能与架构解析,包括网络连接器(Connector)和Servlet容器(Container),并介绍了其处理HTTP请求的工作流程。文章还详细解释了Tomcat的server.xml配置文件,涵盖了从顶级容器Server到子组件Connector、Engine、Host、Context等的配置参数及作用,帮助读者理解Tomcat的内部机制和配置方法。
|
6月前
|
Java 应用服务中间件 Maven
在IntelliJ IDEA中如何配置使用Maven以创建Tomcat环境
所以,别担心这些工具看起来有些吓人,实际上这些都是为了帮助你更好的完成工作的工具,就像超市里的各种烹饪工具一样,尽管它们看起来可能很复杂,但只要你学会用,它们会为你烹饪出一道道美妙的食物。这就是学习新技能的乐趣,让我们一起享受这个过程,攀登知识的高峰!
430 27
|
6月前
|
Java 应用服务中间件 Apache
在IntelliJ IDEA中使用Maven配置Tomcat环境
此配置方法具有较高的实用性,简单易懂。遵循以上步骤,您将能顺利在IntelliJ IDEA中使用Maven配置Tomcat环境,从而进行Web项目的开发和调试。
808 18
|
6月前
|
关系型数据库 MySQL Java
安装和配置JDK、Tomcat、MySQL环境,以及如何在Linux下更改后端端口。
遵循这些步骤,你可以顺利完成JDK、Tomcat、MySQL环境的安装和配置,并在Linux下更改后端端口。祝你顺利!
460 11
|
安全 应用服务中间件 网络安全
Tomcat如何配置PFX证书?
【10月更文挑战第2天】Tomcat如何配置PFX证书?
721 7
|
7月前
|
Java 关系型数据库 MySQL
JDK、Tomcat、MariaDB数据库和Profile多环境的配置与使用
以上就是JDK、Tomcat、MariaDB数据库和Profile多环境的配置与使用的基本步骤。这些步骤可能会因为你的具体需求和环境而有所不同,但是基本的思路是一样的。希望这些信息能够帮助你更好地理解和使用这些工具。
259 17