2017-05-29 24 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需要一段時間開機,靴子很冷,需要時間暖身......)

相關問題