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;
}


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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Recyclerview 刷新「建议收藏」

    Recyclerview 刷新「建议收藏」前言:recyclerview比起listview功能上更加丰富外(如横向列表),在Item复用上也更加灵活,比如listview的某个Item数据需要更新,要通过notifyDataSetChanged方法对全部Item进行刷新,而recyclerview则可以精准刷新。介绍:(1)notifyItemChanged(position)只刷新该position的Item,即只是该Item调用onBindViewHolder,因此如果对数据源进行插、移除操作不能改方法只刷新操作的Item,毕竟该

  • JavaScript中几种常用的设计模式

    JavaScript中几种常用的设计模式设计模式:代码书写经验,为了应对各种场景,经过前人不断的总结,压缩,形成的一套又一套的代码的书写规范,形成了设计模式。1.单例模式单例模式是一种常用的设计模式,如果需要多次创建同一个对象,完成

  • elf格式分析

    elf格式分析

    2021年12月10日
  • roundup与int的区别_notifyall()和notify()区别

    roundup与int的区别_notifyall()和notify()区别 isInterrupted()和interrputed()方法的区别isInterrupted方法是实例方法,interrupted方法是静态方法。Thread.currentThread().isInterrupted()Thread.interrupted()首先说明:wait(),notify(),notifyAll()这些方法由java.lang.Object类提供

    2022年10月28日
  • k8s中实现pod自动扩缩容「建议收藏」

    k8s中实现pod自动扩缩容「建议收藏」如何在k8s中实现基于cpu、内存的pod自动扩缩容来应对非线性资源使用情况,以满足业务需求、节约资源。

  • 写给夏燕第十一个男人「建议收藏」

    写给夏燕第十一个男人「建议收藏」悲哀,(李旧)是她第十一个男人。她想要什么呢???很多男人吗?很多是多少?我是她第十个男人,我原理她了:“说自己以前走的路不可能回头了,叫我不要在过问她以前的事了”。过也两个月后,可还死不改心,还有多少男人被她骗呢?   夏燕(安徽宿松人) 她电话13764996496 15300910532 13917482046   过年回家时,我和夏燕(我第一个女人)认识我不到24小时,就和她发生过关系,还

发表回复

您的电子邮箱地址不会被公开。

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