一、getcontextclassloader的概述
在Java开发中,线程的上下文类加载器(Context ClassLoader)是一个非常关键的概念。每个线程都有一个ClassLoader,由线程的启动器负责初始化。而上下文ClassLoader则是在运行时动态绑定的,用于实现类加载的委托机制。而getcontextclassloader()
方法就是用于获取当前线程的上下文ClassLoader。
public static ClassLoader getcontextclassloader(){
return Thread.currentThread().getContextClassLoader();
}
这个方法是在Thread类中定义的静态方法,使用时不需要创建Thread类的实例。
二、getcontextclassloader的作用
getcontextclassloader()
方法主要用于某些扩展框架或插件中,因为扩展框架或插件是由独立的ClassLoader加载的,所以它们可能无法访问Java应用程序的类。而上下文ClassLoader的概念,让这类框架或插件能够通过getParent()方法动态获取Java应用程序的ClassLoader,并随之继续向上委托ClassLoader,从而解决了访问问题。
另外,在一些不同的OSGI模块化架构中,每个模块都有自己的ClassLoader,在这种情况下,getcontextclassloader()
方法能够非常好地解决模块之间的调用问题。
三、getcontextclassloader的具体实现
在Java中,ClassLoader的继承关系呈现树状结构,从根加载器(Boot ClassLoader)开始,向下分为三层:①Bootstrap ClassLoader;②Extension ClassLoader;③System ClassLoader。其中启动类加载器(Bootstrap ClassLoader)是Java虚拟机实现的一部分,不存在对应的Java类,因此不存在对应的ClassLoader实例对象。这意味着,它并不是一个ClassLoader对象。
在Java应用系统启动后,bootstrap class loader会读取jar文件,并将jar文件中的class文件存放在运行时数据区的方法区中(内存中)。当一个新的class需要被加载时,JVM会先请求bootstrap class loader去加载。如果加载不成功,再依次由extensions class loader、system class loader去进行加载。
在Java中,每个线程都拥有一个上下文ClassLoader,而这个上下文ClassLoader会继承自线程启动时所在的ClassLoader,除非你设置了新的上下文ClassLoader。
对于getcontextclassloader()
方法的实现,我们需要明确两个概念:当前线程和当前线程上下文ClassLoader。Thread.currentThread()
方法返回当前线程,getContextClassLoader()
方法返回当前线程上下文ClassLoader。所以getcontextclassloader()
方法的实现就是通过Thread.currentThread().getContextClassLoader()
获取当前线程上下文ClassLoader。
四、getcontextclassloader的示例代码
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ContextClassLoaderDemo {
public static void main(String[] args) {
Thread.currentThread().setContextClassLoader(ContextClassLoaderDemo.class.getClassLoader().getParent());
//获取当前线程上下文ClassLoader
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
System.out.println("contextClassLoader = " + contextClassLoader);
//使用当前线程上下文ClassLoader加载配置文件
InputStream inputStream = contextClassLoader.getResourceAsStream("test.properties");
//读取配置文件
Properties properties = new Properties();
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
String value = properties.getProperty("key");
System.out.println(value);
}
}
通过这段代码,我们可以看到,在main方法中先设置当前线程的上下文ClassLoader,然后通过getcontextclassloader()
方法获取上下文ClassLoader,并使用它加载配置文件。
五、getcontextclassloader和线程上下文ClassLoader的关系
对于线程上下文ClassLoader,我们需要注意以下几点:
- 如果将当前线程的上下文ClassLoader设置为null,那么默认情况下,它的上下文ClassLoader是父线程的上下文ClassLoader;
- Java应用程序的ClassLoader默认是系统ClassLoader,也就是AppClassLoader;
- Java应用程序的系统ClassLoader,并不是来自于AppClassLoader,而是来自于根ClassLoader的反射调用,这意味着我们可以通过反射获取系统ClassLoader;
- 线程上下文ClassLoader的设定是为了解决一些类加载问题,如果没有明确的需求,应该避免直接操作线程上下文ClassLoader。
六、小结
getcontextclassloader()
方法的作用是获取当前线程的上下文ClassLoader。在Java开发中,ClassLoader的继承关系呈现树状结构,而每个线程都有一个上下文ClassLoader,用于实现类加载的委托机制。getcontextclassloader()
方法通常用于一些扩展框架或插件中,以及在OSGI模块化架构中,用于解决模块之间的调用问题。需要注意的是,线程上下文ClassLoader的设定是为了解决一些类加载问题,如果没有明确的需求,应该避免直接操作线程上下文ClassLoader。