【java 基础】闲话 ClassLoader 和 资源读取

news/2024/7/24 14:32:33 标签: java, 开发语言, ClassLoader

文章目录

接上一篇:【java 基础】闲话 ClassLoader 和 SPI

ClassLoader_6">ClassLoader再探

由上一篇我们知道,不同的 ClassLoader加载的资源范围不同。除了最常见的 java 自己实现的三个类加载器以外,其实还有很多别的加载器。比如spring、 springboot、以及早些年常用的 tomcat,都有自己的加载器。

tomcat的类加载器

tomcat为什么要自定义类加载器,主要有以下几个原因:

  • 作为 web 容器,可以同时运行多个应用。而不同的应用可能使用相同的jar包,但可能版本不同,为了防止出现类冲突,所以必须要对不同的应用进行隔离,方法便是不同的应用使用不同的WebAppClassLoader 实例。
  • 在war包中,类的存储结构是放在/WEB-INF/classes 和/WEB-INF/lib 中,所以类的扫描路径也会不同,需要自定义扫描。
  • 对于常用的包,比如 log4j 之类,如果在每个 classLoader 中都加载一次,是对资源的浪费,所以 tomcat 还存在一个共享的 ShareClassLoader作为WebAppClassLoader 的父加载器。

spring 的类加载器

spring也有自己的加载器:OverridingClassLoader,与双亲委派不同,OverridingClassLoader是自己先尝试加载,在无法加载到的情况下才会启用其父加载器(双亲委派)。即 spring 优先使用自己定义的类。

springboot 的类加载器

我们知道springboot FAT jar 的方式将依赖包都打包到了 BOOT-INF/lib 下,这就导致 java 普通的类加载器无法加载到jar 包中的 jar 包,所以 springboot实现了LaunchedURLClassLoader类加载器来实现自定义加载。

ClassLoader_21">正确获取ClassLoader

通过以上描述我们大概说明了一下类加载器的一些自定义应用。而我们实际使用中,我们怎么获取正确的 ClassLoader呢?
常用的有两种方式获取 ClassLoader

ClassLoader_28">获取当前线程的ContextClassLoader

首先说明一下Thread.currentThread().getContextClassLoader():
在初始化 Thread 时可以指定我们要使用的 ClassLoader,默认情况下是内置的AppClassLoader(在 jvm 启动时指定),而比如 tomcat 等在会在每个应用启动时,初始化自己的 ClassLoader,并且在子线程初始化时会继承父线程的 ClassLoader(Thread 的默认行为)。

ClassLoader_32">加载当前类的ClassLoader

而 this.getClass().getClassLoader()则是获取加载此类的 ClassLoader。每个类对象都会保存加载它自身的 classLoader。还有一个ClassName.class.getClassLoader(); 区别于this.getClass().getClassLoader(),用于静态方法中。

ClassLoader_36">不常用的获取 ClassLoader的方法

ClassLoader.getSystemClassLoader(); //直接获取内置的AppClassLoader
ClassLoader.getPlatformClassLoader(); //直接获取内置的ExtClassLoader

ClassLoader_40">使用ClassLoader的读取资源

通过以上的内容,我们说明了 ClassLoader 的扫描范围,以及如何正确的获取自己想要的 ClassLoader,搞明白了这些内容后,就可以开始应用 ClassLoader 进行资源读取了。

ClassLoader__43">ClassLoader 有几个常用的资源加载方法

  • public URL getResource(String name);
    可以获取到相对于classpath根路径下的资源定位信息,通过 openStream 方法可以开启流读取。如果匹配到多个值,则返回第一个。
  • public Enumeration getResources(String name);
    同getResource,只是会返回所有匹配到的资源。
  • public InputStream getResourceAsStream(String name);
    同getResource,只是会返回直接返回流。
  • public URL getSystemResource(String name);
    不常用,直接获取 AppClassLoader,然后调用getResource(name)方法。范围更小
  • public InputStream getSystemResourceAsStream(String name);
    同getSystemResource方法,只是直接返回流。

注意⚠️:name 不能以/开头。

Class 的资源加载方法

  • public URL getResource(String name);
    如果 name 以/开头,则行为同 ClassLoader 的 getResource(name)方法。如果不以/开头,则路径是相对于当前类所在目录。
  • public InputStream getResourceAsStream(String name);
    同Class.getResource方法,只是直接返回流。

ok,结束收工!


http://www.niftyadmin.cn/n/5412907.html

相关文章

图书馆管理系统(2)

接下来实现系统的子菜单,在写一个子模块的时候,其他子模块先屏蔽起来,因为没实现,代码运行就通不过 屏蔽起来写上todo,后面(Ctrl键F)搜索,找todo来实现 先来实现图书管理模块 第一步,先要把图…

hadoop伪集群部署教程

文章目录 前言一、安装准备1. 安装条件2. 安装jdk3. 配置本节点免密登录 二、安装hadoop1. 下载并解压hadoop2. 设置环境变量2.1 设置hadoop安装目录环境变量2.2. 设置hadoop的root用户环境变量 3. 修改配置文件3.1 修改 etc/hadoop/hadoop-env.sh 文件3.2 修改 etc/hadoop/cor…

2024.3.5

1.select实现tcp服务器端 代码&#xff1a; #include<myhead.h>#define SER_IP "192.168.153.128" #define SER_PORT 8080int create_socket() {int sfd socket(AF_INET, SOCK_STREAM, 0);if(sfd -1){perror("socket error");exit(-1);}printf(&…

Go语法之函数 defer使用

上文我们讲了Go语法的特殊之处&#xff0c;本文讲述Go语法之函数 defer使用。 延迟调用defer是什么&#xff1f; 关键字 defer 的用法类似于面向对象编程语言 Java 和 C# 的 finally 语句块&#xff0c;它一般用于释放某些已分配的资源 defer用于注册一个延迟调用&#xff0…

数据可视化之旅:电商销售看板的制作与心得

作为一名电商工作者&#xff0c;每天都需要与海量的销售数据打交道。在数据海洋中&#xff0c;如何快速准确地找到关键信息&#xff0c;优化销售策略&#xff0c;是摆在我面前的一大挑战。在了解市面上众多可视化产品后&#xff0c;我选择尝试了山海鲸可视化软件&#xff0c;这…

【操作系统学习笔记】文件管理1.2

【操作系统学习笔记】文件管理1.2 参考书籍: 王道考研 视频地址: Bilibili 文件的逻辑结构 无结构文件 文件内部的数据就是一系列的二进制流或字符流组成&#xff0c;又称流式文件&#xff0c;例如 .text 文件 有结构文件 由一组相似的记录组成&#xff0c;又称记录式文件…

Java特性之设计模式【过滤器模式】

一、过滤器模式 概述 ​ 过滤器模式&#xff08;Filter Pattern&#xff09;或标准模式&#xff08;Criteria Pattern&#xff09;是一种设计模式&#xff0c;这种模式允许开发人员使用不同的标准来过滤一组对象&#xff0c;通过逻辑运算以解耦的方式把它们连接起来。这种类型的…

【python--获取每分钟微博热搜】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Python &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; python爬虫 pip install完整代码代码解释阿里云函数计算服务每分钟定时执行测试 pip install beautifuls…