问题描述
Thread t = new Thread() {public void run() {try {Class.forName("test.User");} catch (ClassNotFoundException e) {e.printStackTrace();}System.out.println("child thread:"+ Thread.currentThread().getContextClassLoader());}};t.setContextClassLoader(null);t.start();我在这个线程启动之前把context类加载器设置为bootstrap了,那么run方法第一句加载test。User为什么会成功呢?bootstrap加载器没有父加载器了,它尝试加载User类,而这个类是我自己写的,不是在rt.jar中的,那么为什么会成功加载呢?User类不应该由应用加载类加载的吗?2.还有一个问题,是core java下册中的内容,我不清楚是不是译者的翻译没有到位的问题,他说:偶尔,你也会需要干涉和指定类加载器,考虑下面的例子:*你的应用代码包含一个助手方法,他要调用Class.forName(classNameString)*这个方法是从一个插件类中被调用的。*而classNameString指定的正是一个包含在这个插件的jar中的类。我想象的代码结构可能是这样的。Class Test{ main(){ Util.foo(); }}class Util{ public static void foo(){ Class.forName(classNameString); }}然后他说,插件的作者很合理的期望这个类应该被加载,但是,助手方法的类是由系统类加载器(即应用类加载器)加载的。这正是Class.forName所使用的类加载器。而对于他来说,在插件JAR中的类是不可视的,这种现象称为类加载器倒置。我最后一句话没读懂,如果在eclipse下把插件的jar build进来,不就可以访问到插件中的类了吗?为什么要干涉和指定类加载器? 问题补充:恩,我一开始以为contextClassLoader设置好后,线程就会使用这个loader去加载类了,没想到contextClassLoader原来是给容器用的,java core实现中几乎不使用它。第二个问题我也搞明白了。RednaxelaFX 写道
解决方案
sakop 写道没想到contextClassLoader原来是给容器用的,java core实现中几乎不使用它。第二个问题我也搞明白了。 不啊,Java的核心库里有不少使用了service provider机制的地方都使用到了context class loader。可以留意一下包名是spi结尾的那些。
解决方案二:
第一个问题很好办。Class.forName(className)使用的是“currentLoader”,也就是当前方法所在的类的加载器,而不是context class loader。所以设置context class loader为null完全不影响这个调用。查一下JavaDoc吧。后一问题得看原文…现在手上没这本书回答不了。分数留给后面回答的人了 ^_^