线程上下文类加载器

如上所说 自定义类加载器 ,为解决基础类无法调用类加载器加载用户提供代码的问题,Java 引入了线程上下文类加载器(Thread Context ClassLoader)。这个类加载器默认就是 Application 类加载器,并且可以通过 java.lang.Thread.setContextClassLoaser() 方法进行设置。

// Now create the class loader to use to launch the application
try {
    loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
    throw new InternalError(
"Could not create application class loader" );
}

// Also set the context class loader for the primordial thread.
Thread.currentThread().setContextClassLoader(loader);

那么问题来了,我们使用 ClassLoader.getSystemClassLoader() 方法也可以获取到 Application 类加载器,使用它就可以加载用户类了呀,为什么还需要线程上下文类加载器? 其实直接使用 getSystemClassLoader() 方法获取 AppClassLoader 加载类也可以满足一些情况,但有时候我们需要使用自定义类加载器去加载某个位置的类时,例如Tomcat 使用的线程上下文类加载器并非 AppClassLoader ,而是 Tomcat 自定义类加载器。

以 Tomcat 为例,其每个 Web 应用都有一个对应的类加载器实例,该类加载器使用代理模式,首先尝试去加载某个类,如果找不到再代理给父类加载器这与一般类加载器的顺序是相反的。 这是 Java Servlet 规范中的推荐做法,其目的是使得 Web 应用自己的类的优先级高于 Web 容器提供的类。

更多关于 Tomcat 类加载器的知识,这里暂时先不讲了。