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

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

获得当前上下文的类加载器是啥意思?有啥好处?
 
 
 
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。。。。


欢迎加入我的QQ交流群425783133

### Kubernetes 中 Java 线程上下文类加载器的使用 在 Kubernetes 环境中运行 Spark 应用程序时,`Thread.currentThread().getContextClassLoader()` 是获取当前线程上下文类加载器的重要方法。此方法对于动态加载资源文件、自定义类和其他依赖项非常有用。 当通过 `spark-submit` 提交作业时,所有的参数最终都会传递给 `org.apache.spark.launcher.Main` 类处理[^1]。而在启动过程中,Spark 使用特定的类路径来初始化 JVM 实例: ```bash java -Xmx128m -cp $LAUNCH_CLASSPATH org.apache.spark.launcher.Main ... ``` 这表明,在 Kubernetes 集群内部署的应用程序同样遵循类似的机制。为了确保应用程序能够正确访问所需的类和资源,可以利用 `Thread.currentThread().getContextClassLoader()` 来设置或获取当前线程使用的类加载器实例。 #### 获取并打印当前线程上下文类加载器 可以通过如下方式获取并打印当前线程的上下文类加载器: ```java Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass("com.example.MyClass"); System.out.println(clazz.getName()); ``` 这段代码展示了如何加载指定名称的类,并输出其全限定名。需要注意的是,如果目标类位于 JAR 文件或其他外部位置,则应确保这些资源已正确打包并应用一同部署至 Kubernetes Pod 内部。 #### 设置新的上下文类加载器 有时可能需要临时更改某个操作期间所使用的类加载器。此时可采用以下模式实现这一点: ```java // 保存原始上下文类加载器 ClassLoader originalLoader = Thread.currentThread().getContextClassLoader(); try { // 更改为新创建的URLClassLoader作为上下文类加载器 URL[] urls = { new File("/path/to/your/jar").toURI().toURL() }; ClassLoader customLoader = new URLClassLoader(urls); Thread.currentThread().setContextClassLoader(customLoader); // 执行涉及该类加载器的操作... } finally { // 恢复原来的上下文类加载器 Thread.currentThread().setContextClassLoader(originalLoader); } ``` 上述代码片段说明了在一个安全范围内切换当前线程上下文类加载器的方法。这样做有助于隔离不同部分之间的类加载行为,从而减少潜在冲突的风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值