Thread.currentThread().getContextClassLoader()与Test.class.getClassLoader()区别

Thread.currentThread().getContextClassLoader()与Test.class.getClassLoader()区别忘记以前有没有问过这个问题,总之我现在有看到几个地方有这个:Thread.currentThread().getContextClassLoader()我总是想不出在什么情况下会用这种方式获得一个ClassLoader,因为好像默认情况下,它返回的是和加载应用的ClassLoader是同一个,比如说在一个类Test中写ClassLoader cl = Thread.curren

大家好,又见面了,我是你们的朋友全栈君。


忘记以前有没有问过这个问题,总之我现在有看到几个地方有这个:

Thread.currentThread().getContextClassLoader()

我总是想不出在什么情况下会用这种方式获得一个ClassLoader,因为好像默认情况下,它返回的是和加载应用的ClassLoader是同一个,比如说在一个类Test中写

ClassLoader cl = Thread.currentThread().getContextClassLoader();

为何不直接用Test.class.getClassLoader()

先记录下:有时间整理下。

//  Class.forName(“”).getResourceAsStream(name)


获得当前上下文的类加载器是啥意思?有啥好处?
 
 
 
Java code
?
1
2
3
4
5
6
7
8
9
10
11
public 
class 
Test {
 
    
public 
static 
void 
main(String[] args) {
         
        
// 此时三个ClassLoader是同一个对象
        
System.out.println(Thread.currentThread().getContextClassLoader()); 
// 当前线程的类加载器
        
System.out.println(Test.
class
.getClassLoader()); 
// 当前类的类加载器
        
System.out.println(ClassLoader.getSystemClassLoader()); 
// 系统初始的类加载器
         
    
}
}

如果楼主了解过openfire应该对ClassLoader有比较深的理解。
打个简单的比方,你一个WEB程序,发布到Tomcat里面运行。
首先是执行Tomcat org.apache.catalina.startup.Bootstrap类,这时候的类加载器是ClassLoader.getSystemClassLoader()。
而我们后面的WEB程序,里面的jar、resources都是由Tomcat内部来加载的,所以你在代码中动态加载jar、资源文件的时候,首先应该是使用Thread.currentThread().getContextClassLoader()。如果你使用Test.class.getClassLoader(),可能会导致和当前线程所运行的类加载器不一致(因为Java天生的多线程)。
Test.class.getClassLoader()一般用在getResource,因为你想要获取某个资源文件的时候,这个资源文件的位置是相对固定的。

java的类加载机制(jvm规范)是委托模型,简单的说,如果一个类加载器想要加载一个类,首先它会委托给它的parent去加载,如果它的所有parent都没有成功的加载那么它才会自己亲自来,有点儿像儿子使唤老子的感觉。。jvm也拼爹啊,,,,,
在jvm中默认有三类loaer,bootstrap,ext,app,其中boot最大是爷爷,app最小是孙子,ext中间是爹。
它们有权限访问的classpath也不一样,boot是jdk或jre下面的lib目录,ext是jdk或jre的ext目录,而app是由用户指定的路径,比如用-cp参数指定的目录或jar。他们没有权力访问其他人的classpath,这样问题就来鸟,,,,可能有人会问狗司令大人闲得蛋疼啊,搞这么复杂,据说是为了安全考虑,避免用户的恶心意代码侵蚀jvm,,问题就是当bootstrap或ext想要加载用户指定classpath中的类就会失败,因为这俩货没有权限访问团app路径中的类的,,所以就搞了这么一个不伦不类的contextloader。。。。

资料:

ContextLoaderListener作用详解


(1) org.springframework.web.context.ContextLoaderListener 这个类被定义为监听器,并读取在参数contextConfigLocation中定义的xml 文件,如果不设置contextConfigLocation的初始参数则默认会读取    WEB-INF路径下的 application.xml文件,如果需要自定义了另外的xml 则可以在contextConfigLocation下定义,ContextLoaderListener会读取这些XML文件并产生 WebApplicationContext对象,然后将这个对象放置在ServletContext的属性里,这样我们只要可以得到Servlet就可以得到WebApplicationContext对象,并利用这个对象访问spring 容器管理的bean。
    (2)解析ContextLoadListener的源代码

// 实现了servlet的ServletContextListener接口
public class ContextLoaderListener

     implements ServletContextListener
{

private ContextLoader contextLoader;

// 这个是最重要的,利用contextLoader 来完成所有的工作
public void contextInitialized(ServletContextEvent event)
{

    this.contextLoader = createContextLoader();
    this.contextLoader.initWebApplicationContext(event.getServletContext());
}

protected ContextLoader createContextLoader()
{

    return new ContextLoader();
}

public ContextLoader getContextLoader()
{

    return this.contextLoader;
}

public void contextDestroyed(ServletContextEvent event)
{

    if (this.contextLoader != null)
      this.contextLoader.closeWebApplicationContext(event.getServletContext());
}
}

下面看一下ContextLoader .initWebApplicationContext方法

public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
    throws IllegalStateException, BeansException
{

    if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {

      throw new IllegalStateException(“Cannot initialize context because there is already a root application context present – check whether you have multiple ContextLoader* definitions in your web.xml!”);
    }

    long startTime = System.currentTimeMillis();
    if (this.logger.isInfoEnabled())
      this.logger.info(“Root WebApplicationContext: initialization started”);

    servletContext.log(“Loading Spring root WebApplicationContext”);
    try
    {

      ApplicationContext parent = loadParentContext(servletContext);
     
      // 这里得到WebApplicationContext对象下面具体看一下这个方法是如何实现的
      this.context = createWebApplicationContext(servletContext, parent);
     
    // 将这个对象设置到 servletContext的属性里
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

      if (this.logger.isInfoEnabled()) {

          this.logger.info(“Using context class [” + this.context.getClass().getName() + “] for root WebApplicationContext”);
      }

      if (this.logger.isDebugEnabled()) {

        this.logger.debug(“Published root WebApplicationContext [” + this.context + “] as ServletContext attribute with name [” + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + “]”);
      }

      if (this.logger.isInfoEnabled()) {

        long elapsedTime = System.currentTimeMillis() – startTime;
        this.logger.info(“Root WebApplicationContext: initialization completed in ” + elapsedTime + ” ms”);
      }

      return this.context;
    }

protected WebApplicationContext createWebApplicationContext(ServletContext servletContext, ApplicationContext parent)
    throws BeansException
{

    // 返回在web.xml 中参数contextClass自定义类对应的对象这个类,这个类实现了XmlWebApplicationContext
    // XmlWebApplicationContext继承了AbstractRefreshableWebApplicationContext类中定义的方法protected String[] getConfigLocations() ,这个方法默认可以加载contextConfigLocation中定义的xml 文件,如果你重写了这个方法还可以在任意地方加载你想要的xml文件。

    Class contextClass = determineContextClass(servletContext);
    if (!(ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass))) {

      throw new ApplicationContextException(“Custom context class [” + contextClass.getName() + “] is not of type   ConfigurableWebApplicationContext”);
    }
   
  
// 得到 WebApplicationContext
    ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);

    wac.setParent(parent);
    wac.setServletContext(servletContext);
    String configLocation = servletContext.getInitParameter(“contextConfigLocation”);
    if (configLocation != null) {

      wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation, “,; \t\n”));
    }

    wac.refresh();
    return wac;
}


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/134558.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • tl494cn逆变器电路图_用TL494制作的逆变电源[通俗易懂]

    tl494cn逆变器电路图_用TL494制作的逆变电源[通俗易懂]TL494集成块广泛应用在开关电源,其内部集成有PWM、三角波发生器、电池欠压检测,+5V电压基准等电路,具有外接元件少,控制稳定的特点。笔者在网上查阅大量资料,自制了一款准正弦波300W逆变器,采用直流12V电瓶供电,可供小功率单相电机、日光灯等电感性负载用电,电路如附图所示。该逆变板工作频率由TL494⑤、⑥脚外接阻容元件确定,本例为2.2kHz左右。该频率的大小直接影响功率场效应管的功率损耗…

    2022年6月3日
    157
  • mhdd测试hdd硬盘软件,硬盘检测工具mhdd

    mhdd测试hdd硬盘软件,硬盘检测工具mhdd硬盘检测工具mhdd是一款能够修复坏道的专业硬盘检测工具,MHDD硬盘检测工具可以不依赖于主板BIOS直接访问IDE口,可以访问128G的超大容量硬盘,即使你用的是286电脑,无需BIOS支持,也无需任何中断支持。且MHDD还能够帮使用者修复坏轨,让使用者能够继续延续该硬盘的生命余光。软件功能:1、无论以CHS还是以LBA模式,都可以访问到128G的超大容量硬盘(可访问的扇区范围从512到3743…

    2022年7月12日
    18
  • 基于ffmpeg+nginx+UscreenCapture的局域网直播系统搭建「建议收藏」

    基于ffmpeg+nginx+UscreenCapture的局域网直播系统搭建「建议收藏」基于ffmpeg+nginx+UscreenCapture的局域网直播系统搭建

    2022年4月21日
    133
  • netstat命令详解

    netstat命令详解简介netstat命令用于显示各种网络相关信息,如网络连接,路由表,接口状态(InterfaceStatistics),masquerade连接,多播成员(MulticastMember

    2022年7月3日
    24
  • 如何将pdf转换成word的3种免费方法「建议收藏」

    如何将pdf转换成word的3种免费方法「建议收藏」怎样将PDF转成Word?这是很多网友经常问到的问题,PDF转换成Word利用一些小技巧和工具,你会发现是很容易的,以下的PDF转Word的3种免费方法你一定要看一看。1、“复制/粘贴”大法在寻找如何将PDF转换成Word的“高级”办法之前,不妨先试一下最傻瓜的方法:首先用极速PDF阅读器打开PDF文档,选择文本内容后右击选择“复制选择内容”或直接使用“全选”;接着新建一个Word文档后,直接将内容在Word中粘贴即可。如果文档格式不复杂,这样得到的Word就够用了,当然有些可能排版会比较乱。2、G

    2022年6月1日
    61
  • 回归分析(stata实例详细解答过程)[通俗易懂]

    回归分析(stata实例详细解答过程)[通俗易懂]现有某电商平台846条关于婴幼儿奶粉的销售信息,每条信息由11个指标组成。其中,评价量可以从一个侧面反映顾客对产品的关注度。请对所给数据进行以下方面的分析,要求最终的分析将不仅仅有益于商家,更有益于宝妈们为宝贝选择适合自己的奶粉。(1)以评价量为因变量,分析其它变量和评价量之间的关系。(2)以评价量为因变量,研究影响评价量的重要因素。我们运用stata软件解决此问题。第一问在第一问中要求我们,以评价量为因变量,分析其它变量和评价量之间的关系。我们在这里用回归分析,…

    2022年8月30日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号