深入理解ContextClassLoader加载器

 更新时间:2023年10月07日 10:08:25   作者:西魏陶渊明  
这篇文章主要介绍了深入理解ContextClassLoader加载器,Thread context class loader存在的目的主要是为了解决parent delegation机制下无法干净的解决的问题,需要的朋友可以参考下

ContextClassLoader

Thread.currentThread().getContextClassLoader(); - 从方法名字来看,应该是获取当前上下文的类加载器 搞清楚这个问题, 当你在出现资源加载不到的时候就很容器解决

那么问题来了,为什么要这样设计? 解决了什么样的设计问题? 解决了什么样的开发问题? 

  • 解决委派双亲加载模式的缺点
  • 实现了JNDI等
  • 解决开发中,文件加载不到的异常
Thread.currentThread().getContextClassLoader();
this.getClass().getClassLoader();

类加载器之前一直迷惑,终于这个问题在一篇博客的回答中,找到了清晰易懂的解释

原文是这样的:

Thread context class loader存在的目的主要是为了解决parent delegation机制下无法干净的解决的问题。

假如有下述委派链: ClassLoader A -> System class loader -> Extension class loader -> Bootstrap class loader

那么委派链左边的ClassLoader就可以很自然的使用右边的ClassLoader所加载的类。

但如果情况要反过来,是右边的ClassLoader所加载的代码需要反过来去找委派链靠左边的ClassLoader去加载东西怎么办呢?没辙,parent delegation是单向的,没办法反过来从右边找左边.*

类加载器的委派双亲模式?

就是说当我们this.getClass().getClassLoader();可以获取到所有已经加载过的文件, 但是 System class loader -> Extension class loader -> Bootstrap class loader 就获取不到 ClassLoader A 能加载到的信息,那么怎么办呢? 于是,Thread就把当前的类加载器,给保存下来了,其他加载器,需要的时候,就把当前线程的加载器,获取到.

那么什么场景下,会遇到这种情况那,当通常发生在有些JVM核心代码必须动态加载由应用程序开发人员提供的资源时eg:

JNDI

JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口

在系统中,要调用开发者的资源,此时就遇到了这种情况

JAX和rt.jar 因为是两个加载器加载的 那么BootStrap需要加载Ext的资源,怎么办? 这不是与委托机制相反了吗? 所以就不能只依赖委派双亲模式,那么怎么做

然后我们看一波,Thread源码的注释,提供了,获取上下文加载器方法 Thread.currentThread().getContextClassLoader()

Thread

 /* The context ClassLoader for this thread */
    private ClassLoader contextClassLoader;

问题:

项目中需要加载应用配置,加载不到,需要用ClassPathResource

问题同上,父加载器要加载应用配置,因此需要调用上下文加载器

代码块分析

//获取文件绝对地址,并不是jar里面的文件路径
URL resource = BlmSignature.class.getClassLoader().getResource(keystoreFilePath);
String path = resource.getPath();
//当发布到线上只发布jar文件, 所以就会报异常,找不到
FileInputStream keystoreinputStream=new FileInputStream(path);
//正确的做法是,获取到jar包里面的文件,需要注意类加载是否能加载到的问题,
//1. Spring工具
keystorePath = "classpath:"+keystoreFilePath;
ClassPathResource classPathResource = new ClassPathResource(keystorePath);
InputStream keystoreinputStream = classPathResource.getInputStream();
//使用类加载器加载classpath里面的
//指定Thread.currentThread().getContextClassLoader();加载器
SmileClassPathResource smileClassPathResource = new SmileClassPathResource(keystoreFilePath);
InputStream  keystoreinputStream=smileClassPathResource.getInputStream();

SmileClassPathResource源码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
 * @Package: org.smileframework.tool.io
 * @Description: 加载配置文件
 * @author: liuxin
 * @date: 2017/12/19 上午9:23
 */
public class SmileClassPathResource {
    private final String path;
    private ClassLoader classLoader;
    public SmileClassPathResource(String name) {
        this(name, getDefaultClassLoader());
    }
    public SmileClassPathResource(String name, ClassLoader classLoader) {
        this.path = name;
        this.classLoader = classLoader;
    }
    public static ClassLoader getDefaultClassLoader() {
        ClassLoader cl = null;
        try {
            cl = Thread.currentThread().getContextClassLoader();
        } catch (Throwable var3) {
            ;
        }
        if(cl == null) {
            cl = ClassUtils.class.getClassLoader();
            if(cl == null) {
                try {
                    cl = ClassLoader.getSystemClassLoader();
                } catch (Throwable var2) {
                    ;
                }
            }
        }
        return cl;
    }
    public InputStream getInputStream() {
        InputStream is;
        if (this.classLoader != null) {
            is = this.classLoader.getResourceAsStream(this.path);
        } else {//当还是加载不到,调用上层加载器
            is = ClassLoader.getSystemResourceAsStream(this.path);
        }
        if (is == null) {
            throw new RuntimeException(path + " cannot be opened because it does not exist");
        } else {
            return is;
        }
    }
    public String getResourceStreamAsString() {
        InputStream is = getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
    public static void main(String[] args) {
        SmileClassPathResource classPathResource = new SmileClassPathResource("logback.xml");
        System.out.println(classPathResource.getResourceStreamAsString());
    }
}

到此这篇关于深入理解ContextClassLoader加载器的文章就介绍到这了,更多相关ContextClassLoader加载器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 如何在java 8 stream表达式实现if/else逻辑

    如何在java 8 stream表达式实现if/else逻辑

    这篇文章主要介绍了如何在java 8 stream表达式实现if/else逻辑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • 详解Java实现多线程的三种方式

    详解Java实现多线程的三种方式

    线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。本文总结了Java多线程是三种实现方式,需要的可以参考一下
    2022-03-03
  • Java优雅的处理金钱问题(BigDecimal)

    Java优雅的处理金钱问题(BigDecimal)

    本文主要介绍了Java优雅的处理金钱问题(BigDecimal),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • springMVC+ajax实现文件上传且带进度条实例

    springMVC+ajax实现文件上传且带进度条实例

    本篇文章主要介绍了springMVC+ajax实现文件上传且带进度条实例,具有一定的参考价值,有兴趣的可以了解一下。
    2017-01-01
  • Java Calendar类使用之日期和时间处理指南

    Java Calendar类使用之日期和时间处理指南

    这篇文章主要给大家介绍了关于Java Calendar类使用之日期和时间处理指南的相关资料,Calendar类是Java中用于处理日期和时间的抽象类,它提供了一种独立于特定日历系统的方式来处理日期和时间,需要的朋友可以参考下
    2023-12-12
  • java 使用线程做的一个简单的ATM存取款实例代码

    java 使用线程做的一个简单的ATM存取款实例代码

    线程 Thread 类,和 Runable 接口 比较两者的特点和应用领域.可以,直接继承线程Thread类。该方法编写简单,可以直接操作线程,适用于单重继承情况,因而不能在继承其他类,下面我们来看一个实例
    2013-08-08
  • 快速了解Maven

    快速了解Maven

    这篇文章主要介绍了快速了解Maven,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • 如何解决springmvc文件下载,内容损坏的问题

    如何解决springmvc文件下载,内容损坏的问题

    这篇文章主要介绍了解决springmvc文件下载,内容损坏的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • JavaIO字符操作和对象操作示例详解

    JavaIO字符操作和对象操作示例详解

    这篇文章主要为大家介绍了JavaIO字符操作和对象操作示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • 详解SpringBoot如何使用JWT实现身份认证和授权

    详解SpringBoot如何使用JWT实现身份认证和授权

    JSON Web Token(JWT)是一种用于在网络应用之间安全传递信息的开放标准,本文主要为大家介绍了如何在Spring Boot中使用JWT实现身份认证和授权,需要的可以了解下
    2023-10-10

最新评论