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在加载类前,先委派给双亲去加载类; 在有双亲委派模式的情况下,启动类装载器可以抢在标准扩展类装载器之前去装载类,而标准扩展类装载器可以抢在系统类装载器之前去装载那个类,类路径类装载器又可以抢在用户自定义类装载器之前去装载它,用这种方法,类装载器的体系结构就可以防止不可靠的代码用它们自己的版本来替代可信任的类。
952 0
|
1月前
|
安全 应用服务中间件 网络安全
Tomcat如何配置PFX证书?
【10月更文挑战第2天】Tomcat如何配置PFX证书?
186 7
|
1月前
|
存储 算法 应用服务中间件
Tomcat如何配置JKS证书?
【10月更文挑战第2天】Tomcat如何配置JKS证书?
272 4
|
3月前
|
网络协议 Java 应用服务中间件
tomcat配置域名及HTTPS
tomcat配置域名及HTTPS
|
3月前
|
Java 应用服务中间件 Windows
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
|
1月前
|
Java Shell 应用服务中间件
Mac系统下配置环境变量:Javajdk、maven、tomcat 环境变量配置及对应配置文件
这篇文章介绍了如何在Mac系统下配置Java JDK、Maven和Tomcat的环境变量,包括配置文件的选择、解决环境变量在zsh shell中无效的问题、查看和设置系统环境变量的方法,以及JDK和Maven的下载、配置和测试步骤。
1402 1
Mac系统下配置环境变量:Javajdk、maven、tomcat 环境变量配置及对应配置文件
|
2月前
|
应用服务中间件 Docker 容器
docker应用部署---Tomcat的部署配置
这篇文章介绍了如何使用Docker部署Tomcat服务器,包括搜索和拉取Tomcat镜像、创建容器并设置端口映射和目录映射,以及如何创建一个HTML页面并使用外部机器访问Tomcat服务器。
docker应用部署---Tomcat的部署配置
|
1月前
apache+tomcat配置多站点集群的方法
apache+tomcat配置多站点集群的方法
33 4
|
1月前
|
负载均衡 应用服务中间件 Apache
Tomcat负载均衡原理详解及配置Apache2.2.22+Tomcat7
Tomcat负载均衡原理详解及配置Apache2.2.22+Tomcat7
37 3