Thread的getContextClassLoader()

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

获得当前上下文的类加载器是啥意思?有啥好处?
...全文
4487 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
fishmanxiaomai1987 2013-11-19
  • 打赏
  • 举报
回复
试着回答一下, 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。。。。
fainfy 2011-09-09
  • 打赏
  • 举报
回复

final ClassLoader parent = findParentClassLoader();

String libDirString = System.getProperty("openfire.lib.dir");

File libDir;
if (libDirString != null) {
// If the lib directory property has been specified and it actually
// exists use it, else use the default
libDir = new File(libDirString);
if (!libDir.exists()) {
Log.warn("Lib directory " + libDirString +
" does not exist. Using default " + DEFAULT_LIB_DIR);
libDir = new File(DEFAULT_LIB_DIR);
}
}
else {
libDir = new File(DEFAULT_LIB_DIR);
}

// Unpack any pack files.
unpackArchives(libDir, true);

String adminLibDirString = System.getProperty("openfireHome");
if (adminLibDirString == null) {
adminLibDirString = DEFAULT_ADMIN_LIB_DIR;
}
else {
adminLibDirString = adminLibDirString+"/plugins/admin/webapp/WEB-INF/lib";
}
File adminLibDir = new File(adminLibDirString);
if (adminLibDir.exists()) {
unpackArchives(adminLibDir, false);
}
else {
Log.warn("Admin Lib Directory " + adminLibDirString +
" does not exist. Web admin console may not work.");
}

ClassLoader loader = new JiveClassLoader(parent, libDir);

Thread.currentThread().setContextClassLoader(loader);
Class containerClass = loader.loadClass(
"org.jivesoftware.openfire.XMPPServer");
containerClass.newInstance();
fainfy 2011-09-09
  • 打赏
  • 举报
回复

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,因为你想要获取某个资源文件的时候,这个资源文件的位置是相对固定的。

建议楼主去查看一下openfire或者tomcat内部的源码,对ClassLoader会有比较深的理解。
在openfire里面,openfire使用的类加载器,以及每个插件使用的类加载器都不一样。
dreamhunter_lan 2011-09-09
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 beowulf2005 的回复:]
假设要装载的类,通过当前类的Classloader链装载不了,那就得设ContextClassLoader
[/Quote]
举个例子看看
安心逍遥 2011-09-09
  • 打赏
  • 举报
回复
通过当前类的Classloader链装载不了,那就得设ContextClassLoader
beowulf2005 2011-09-09
  • 打赏
  • 举报
回复
假设要装载的类,通过当前类的Classloader链装载不了,那就得设ContextClassLoader
huntor 2011-09-09
  • 打赏
  • 举报
回复

62,633

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧