2017-05-29 54 views
5
lihaoyi test$ tree 
. 
└── Foo.scala 

0 directories, 1 file 

lihaoyi test$ cat Foo.scala 
object Main{ 
    def main(args: Array[String]): Unit = { 
    println(getClass.getClassLoader.getResourceAsStream("java/lang/String.class")) 
    println(getClass.getClassLoader.getClass) 
    println(Thread.currentThread().getContextClassLoader.getResourceAsStream("java/lang/String.class")) 
    println(Thread.currentThread().getContextClassLoader.getClass) 
    } 
} 

lihaoyi test$ sbt run 
[info] Loading global plugins from /Users/lihaoyi/.sbt/0.13/plugins 
[info] Set current project to test (in build file:/Users/lihaoyi/Dropbox/Workspace/test/) 
[info] Updating {file:/Users/lihaoyi/Dropbox/Workspace/test/}test... 
[info] Resolving org.fusesource.jansi#jansi;1.4 ... 
[info] Done updating. 
[info] Compiling 1 Scala source to /Users/lihaoyi/Dropbox/Workspace/test/target/scala-2.10/classes... 
[info] Running Main 
[email protected]8ff2 
class sbt.classpath.ClasspathUtilities$$anon$1 
null 
class sbt.classpath.ClasspathFilter 
[success] Total time: 2 s, completed 29 May, 2017 4:14:11 PM 

lihaoyi test$ 

在这里,我们可以看到getClass.getClassLoaderThread.currentThread.getContextClassLoader返回不同的值。更重要的是,Thread.currentThread.getContextClassLoader似乎拒绝加载java/lang/String.class,而另一个可以。为什么SBT的线程上下文类加载器不能将JDK类文件加载为资源?

值得注意的是,当我运行使用像scalac/scala,或java外部工具的jar文件,这两个类加载器能加载类文件作为资源

lihaoyi test$ scalac Foo.scala 

lihaoyi test$ scala Main 
[email protected]b28cdfa 
class scala.reflect.internal.util.ScalaClassLoader$URLClassLoader 
[email protected]724f 
class scala.reflect.internal.util.ScalaClassLoader$URLClassLoader 

我希望SBT同样的行为:使Main.getClass.getClassLoaderThread.currentThread().getContextClassLoader都能够将java/lang/String.class作为资源加载。是什么赋予了?

回答

3

Jason Zaugg(retronym)的sbt launcher notes提供了一些提示。

SBT /发射器是一个小型的Scala应用程序,自举(典型地,SBT)中描述的配置文件,并且经由常春藤依赖性解析来源于任意的Scala程序。

这创建了一个包含Scala 2.10.6的子类加载器。这个包含SBT本身和xsbti/interface-0.13.11.jar。

对于插件代码,Scala编译器或用户代码创建子类加载器时,SBT需要使用非标准类加载器委派来选择性地隐藏类。

一些更多的提示在SBT 0.13来源:

def makeLoader(classpath: Seq[File], instance: ScalaInstance, nativeTemp: File): ClassLoader = 
    filterByClasspath(classpath, makeLoader(classpath, instance.loader, instance, nativeTemp)) 


def makeLoader(classpath: Seq[File], parent: ClassLoader, instance: ScalaInstance, nativeTemp: File): ClassLoader = 
    toLoader(classpath, parent, createClasspathResources(classpath, instance), nativeTemp) 

基本上SBT是具有任意的Scala的Java应用程序的厨房水槽版本和代码,以及您的测试库以及Oracle/OpenJDK的Java libr元。要构造一个有意义的类路径而不重复加载它们,它将创建一个类加载器的层次结构,每个类都按某些条件进行过滤。 (我认为)

1

值得注意的是,解决这个问题的方法之一是设置

(fork in run) := true, 

(connectInput in run) := true, 
(outputStrategy in run) := Some(StdoutOutput), 

这似乎解决了这个问题,(Thread.currentThread().getContextClassLoader.getResourceAsStream("java/lang/String.class")现在工作),但引入了其他无关的问题(分叉JVM需要一段时间开机,靴子很冷,需要时间暖身......)

相关问题