为什么Clojure默认使用上下文类加载器?

19

为什么默认情况下将 use-context-classloader 设为 true?

为什么Clojure不使用当前的类加载器?


4
现在正在阅读这篇文章:http://www.javaworld.com/javaqa/2003-06/01-qa-0606-load.html,这对我来说是一个有趣的话题,作者得出的结论是,上下文类加载器不太可能被框架覆盖,因此行为更加可预测。对于这个问题的回答,我会留给真正了解的人去回答。 - Jason Sperske
1个回答

6

如果需要覆盖其行为,您可以通过将clojure.lang.Compiler.LOADER设置为类加载器来实现。

final ClassLoader ccl= ClojurePlugin.class.getClassLoader();
clojure.lang.Var.pushThreadBindings(clojure.lang.RT.map( clojure.lang.Compiler.LOADER, ccl) );
try {
  ...
  clojure.lang.RT.loadResourceScript( cljFile );
  ...
}finally{
  clojure.lang.RT.popThreadBindings();
}

其中ClojurePlugin是你的类名。

但是当你第一次使用RT类时(即当RT类被加载时),它将使用上下文类加载器来加载即 clojure/core,因此你可能想将上述代码包装成:

ClassLoader previous = Thread.currentThread().getContextClassLoader();
final ClassLoader parentClassLoader = ClojurePlugin.class.getClassLoader();
Thread.currentThread().setContextClassLoader(parentClassLoader);
try {
  ...
  //above code here
  ...
} finally {
  Thread.currentThread().setContextClassLoader(previous);
}

否则,您可能会遇到一些错误消息,例如:
Caused by: java.io.FileNotFoundException: Could not locate clojure/core__init.class or clojure/core.clj on classpath:
        at clojure.lang.RT.load(RT.java:432)
        at clojure.lang.RT.load(RT.java:400)
        at clojure.lang.RT.doInit(RT.java:436)
        at clojure.lang.RT.<clinit>(RT.java:318)
        ... 16 more

否则,如果你只做了后者而没做前者,你会得到类似以下这样的结果:
21:10:59 [SEVERE] java.io.FileNotFoundException: Could not locate Clojure resource on classpath: cljminecraft/core.clj
21:10:59 [SEVERE]       at clojure.lang.RT.loadResourceScript(RT.java:366)
21:10:59 [SEVERE]       at clojure.lang.RT.loadResourceScript(RT.java:346)
21:10:59 [SEVERE]       at clojure.lang.RT.loadResourceScript(RT.java:338)
21:10:59 [SEVERE]       at cljminecraft.ClojurePlugin.loadClojureFile(ClojurePlugin.java:25)
21:10:59 [SEVERE]       at cljminecraft.ClojurePlugin.loadClojureNameSpace(ClojurePlugin.java:38)
21:10:59 [SEVERE]       at cljminecraft.ClojurePlugin.start(ClojurePlugin.java:53)
21:10:59 [SEVERE]       at cljminecraft.BasePlugin.onEnable(BasePlugin.java:235)
21:10:59 [SEVERE]       at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:217)
21:10:59 [SEVERE]       at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:374)
21:10:59 [SEVERE]       at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:381)
21:10:59 [SEVERE]       at org.bukkit.craftbukkit.CraftServer.loadPlugin(CraftServer.java:270)
21:10:59 [SEVERE]       at org.bukkit.craftbukkit.CraftServer.enablePlugins(CraftServer.java:252)
21:10:59 [SEVERE]       at net.minecraft.server.MinecraftServer.j(MinecraftServer.java:320)
21:10:59 [SEVERE]       at net.minecraft.server.MinecraftServer.e(MinecraftServer.java:299)
21:10:59 [SEVERE]       at net.minecraft.server.MinecraftServer.a(MinecraftServer.java:258)
21:10:59 [SEVERE]       at net.minecraft.server.DedicatedServer.init(DedicatedServer.java:147)
21:10:59 [SEVERE]       at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:398)
21:10:59 [SEVERE]       at net.minecraft.server.ThreadServerApplication.run(SourceFile:856)

如果您不这样做(但仍然调用类似clojure.lang.RT.loadResourceScript(cljFile);的内容),那么您将得到第一个错误(显然)。


我实际上使用了不同的ccl(而不是类中的那个):final clojure.lang.DynamicClassLoader ccl = (clojure.lang.DynamicClassLoader)AccessController.doPrivileged( new PrivilegedAction() { @Override public Object run() { return new clojure.lang.DynamicClassLoader( ClojurePlugin.class.getClassLoader()); } }); 之后,我通过ccl.addURL(jarURL)将jar文件添加到其类路径中。 - basicsensei
1
有趣的解决方案。最终我修改了Clojure本身的源代码,将类加载器改为当前的类加载器而不是上下文类加载器:https://groups.google.com/forum/?fromgroups=#!topic/clojure/gRhD0HOwFGc - mudgen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接