斯卡拉类加载器混乱 [英] scala classloaders confusion

查看:84
本文介绍了斯卡拉类加载器混乱的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下测试程序(使用scala 2.9.0.1)

 对象测试
{
def main(args:Array [String])= {
println(ClassLoader.getSystemClassLoader.getResource( toto))
println(this.getClass.getClassLoader.getResource( toto))
println(classOf [Object] .getClassLoader)
}
}

我编译并使用包含文件 toto的 -cp / tmp运行它,得到以下输出:

 
文件:/ tmp / toto

=>系统类加载器不包含类路径



=> Object类没有类加载器!



我错过了一些东西吗?

谢谢,
Arjun

解决方案

第二个null由 java.lang.Class#getClassLoader()


返回该类的类加载器。一些实现可能使用
null来代表引导类加载器。如果此类是由引导程序
类加载器加载的,则此方法在此类实现中将返回
null。


因此,这就是为什么 classOf [Object] .getClassLoader 返回null的原因,它是由引导类加载器加载的(它位于rt.jar中,更具体地说,它位于jar中在$ JAVA_HOME / lib中。)



第一个null较难解释。似乎Scala保持了系统类加载器的原样,仅在其自己的类加载器(scala / util / ClassLoader.scala中的ScalaClassLoader)中添加了-cp选项。



使用以下命令:

  object Test {
def main(args:Array [String])= {
println(ClassLoader.getSystemClassLoader)
println(this.getClass.getClassLoader)
println(classOf [Object] .getClassLoader)
}
}

并运行以下命令:

  $ scala -cp / temp测试

我们得到以下输出:

  sun.misc.Launcher$AppClassLoader@11b86e7 
URLClassLoader(
文件:/ C:/developpement/utils/jdk1.6.0_22/ jre / lib / resources.jar
文件:/ C:/developpement/utils/jdk1.6.0_22/jre/lib/rt.jar
文件:/ C:/developpement/utils/jdk1.6.0 _22 / jre / lib / jsse.jar
文件:/ C:/developpement/utils/jdk1.6.0_22/jre/lib/jce.jar
文件:/ C:/ developpement / utils /jdk1.6.0_22/jre/lib/charsets.jar
文件:/ C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/dnsns.jar
文件:/ C: /developpement/utils/jdk1.6.0_22/jre/lib/ext/localedata.jar
文件:/ C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/sunjce_provider.jar
文件:/ C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/sunmscapi.jar
文件:/ C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/ sunpkcs11.jar
文件:/ C:/DEVELO~1/scala/SCALA-~1.1/bin /../ lib / jline.jar
文件:/ C:/ DEVELO〜1 / scala / SCALA-〜1.1 / bin /../ lib / scala-compiler.jar
文件:/ C:/DEVELO~1/scala/SCALA-~1.1/bin /../ lib / scala-dbc.jar
文件:/ C:/DEVELO~1/scala/SCALA-~1.1/bin /../ lib / scala-library.jar
文件:/ C:/ DEVELO〜1 / scala / SCALA -〜1.1 / bin /../ lib / scala-swing.jar
文件:/ C:/DEVELO~1/scala/SCALA-~1.1/bin /../ lib / scalap.jar
文件:/ C:/ temp /


null

因此系统类加载器保持不变,但是Scala类加载器从-cp中获得了添加到其中的项目。 / p>

故事的寓意:如果要从类路径访问资源,请不要在Scala中使用系统类加载器。



编辑:好的,我对此进行了更多研究,并且scala.bat正在执行以下命令行(在纯Windows下,已缩短可读性)

  java.exe -Xmx256M -Xms32M -Dscala.home = xxx -cp libsfromscalahome scala.tools.nsc.MainGenericRunner -cp / temp测试

因此,命令行中的-cp选项仅作为选项传递给MainGenericRunner,而不是 java。我相信,通过查看代码,您可以在unix下为scala指定-toolcp选项,以获取Java类路径中包含的内容。诸如此类(完全未经测试):

  $ scala -toolcp / temp测试

此选项在scala.bat中不可用。这意味着,如果您在Windows下工作,则必须使用

  println(this.getClass.getClassLoader .getResource( toto))

我在 Scala语言问题,但是如果您遇到问题,请提出问题并提交修复程序。我敢肯定他们会很高兴的:-)



编辑:我已将此问题发布为 SI 5062 -toolcp应该在Windows的scala.bat 中可用,并在 github


Please consider the following test program (using scala 2.9.0.1)

object test
{
  def main(args:Array[String]) = {
    println(ClassLoader.getSystemClassLoader.getResource("toto"))
    println(this.getClass.getClassLoader.getResource("toto"))
    println(classOf[Object].getClassLoader)
  }
}

I compile it and run it with "-cp /tmp" containing a file "toto", and I get the following output:

null
file:/tmp/toto
null

=> the system classloader does not contain the classpath

=> the Object class has no classloader!

Am I missing something there or is it a (big) bug in scala?!

Thanks, Arjun

解决方案

The second null is explained by java.lang.Class#getClassLoader()

Returns the class loader for the class. Some implementations may use null to represent the bootstrap class loader. This method will return null in such implementations if this class was loaded by the bootstrap class loader.

So, this is why classOf[Object].getClassLoader returns null, it's loaded by the bootstrap classloader (it is in rt.jar, more specifically, it is in a jar which is in $JAVA_HOME/lib).

The first null is harder to explain. It seems that Scala leaves the system classloader as-is, and only adds the options -cp to it's own classloader (ScalaClassLoader in scala/util/ClassLoader.scala).

Using the following:

object Test {
  def main(args:Array[String]) = {
    println(ClassLoader.getSystemClassLoader)
    println(this.getClass.getClassLoader)
    println(classOf[Object].getClassLoader)
  }
}

and running it with:

$ scala -cp /temp Test

we get the following output:

sun.misc.Launcher$AppClassLoader@11b86e7
URLClassLoader(
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/resources.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/rt.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/jsse.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/jce.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/charsets.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/dnsns.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/localedata.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/sunjce_provider.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/sunmscapi.jar
  file:/C:/developpement/utils/jdk1.6.0_22/jre/lib/ext/sunpkcs11.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/jline.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/scala-compiler.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/scala-dbc.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/scala-library.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/scala-swing.jar
  file:/C:/DEVELO~1/scala/SCALA-~1.1/bin/../lib/scalap.jar
  file:/C:/temp/
)

null

So the System classloader is left untouched, but the Scala classloader gets the items from -cp added to it.

Moral of the story: don't use the system classloader in Scala if you want to access resources from the classpath.

EDIT: Ok, I've investigated this a bit more, and scala.bat is executing the following command line (under pure Windows, shortened for readability)

java.exe -Xmx256M -Xms32M -Dscala.home="xxx" -cp "libsfromscalahome" scala.tools.nsc.MainGenericRunner  -cp /temp Test

So the -cp option from the command line is only being passed as an option to MainGenericRunner, not the java. I believe, from looking at the code, that under unix you can specify the -toolcp option to scala to get something included in the java classpath. Something like (totally untested):

$ scala -toolcp /temp Test

This option isn't available in scala.bat. Which means if you're working under windows, you'll have to get the resources using

println(this.getClass.getClassLoader.getResource("toto"))

I couldn't find an issue in the Scala Lang Issues, but if it's a problem for you, raise an issue and submit a fix. I'm sure they'll be thrilled :-)

EDIT: I have raised this as issue SI 5062 -toolcp should be available on windows, in the scala.bat, and provided a pull request for it on github.

这篇关于斯卡拉类加载器混乱的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆