путаница в загрузчиках классов scala

#scala #classloader

#scala #загрузчик классов

Вопрос:

Пожалуйста, рассмотрите следующую тестовую программу (с использованием 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)
  }
}
  

Я компилирую его и запускаю с помощью «-cp / tmp», содержащего файл «toto», и получаю следующий результат:

 null
file:/tmp/toto
null
  

=> системный загрузчик классов не содержит пути к классу

=> класс Object не имеет загрузчика классов!

Я что-то упускаю или это (большая) ошибка в scala ?!

Спасибо, Арджун

Ответ №1:

Второй нуль объясняется java.lang.Class#getClassLoader()

Возвращает загрузчик класса для класса. Некоторые реализации могут использовать null для представления загрузчика классов начальной загрузки. Этот метод вернет null в таких реализациях, если этот класс был загружен загрузчиком классов bootstrap.

Итак, вот почему classOf[Object].getClassLoader возвращает null, он загружается загрузчиком классов начальной загрузки (он находится в rt.jar , более конкретно, он находится в jar, который находится в $JAVA_HOME/lib).

Первый null объяснить сложнее. Кажется, что Scala оставляет системный загрузчик классов как есть и только добавляет options -cp к своему собственному загрузчику классов (ScalaClassLoader в scala/util/ClassLoader.scala).

Используя следующее:

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

и запуск его с:

 $ scala -cp /temp Test
  

мы получаем следующий вывод:

 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
  

Таким образом, системный загрузчик классов остается нетронутым, но загрузчик классов Scala получает добавленные к нему элементы из -cp .

Мораль истории: не используйте системный загрузчик классов в Scala, если вы хотите получить доступ к ресурсам из пути к классам.

РЕДАКТИРОВАТЬ: Хорошо, я исследовал это немного подробнее, и scala.bat выполняет следующую командную строку (в чистой Windows, сокращенную для удобства чтения)

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

Таким образом, параметр -cp из командной строки передается только в качестве опции в MainGenericRunner, а не в java. Я полагаю, глядя на код, что в unix вы можете указать параметр -toolcp для scala, чтобы получить что-то включенное в путь к классу java. Что-то вроде (полностью непроверенный):

 $ scala -toolcp /temp Test
  

Эта опция недоступна в scala.bat. Это означает, что если вы работаете под Windows, вам придется получать ресурсы с помощью

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

Я не смог найти проблему в проблемах Scala Lang, но если это проблема для вас, поднимите проблему и отправьте исправление. Я уверен, что они будут в восторге 🙂

РЕДАКТИРОВАТЬ: я поднял этот вопрос как проблему SI 5062 -toolcp должен быть доступен в Windows, в scala.bat, и предоставил запрос на извлечение для него на github.

Ответ №2:

Из статьи загрузчика классов в Википедии:

Загрузчик системных классов загружает код, найденный в java.class.path, который сопоставляется с системной переменной CLASSPATH.

Не уверен насчет второго нуля. Может быть, кто-то еще может это прояснить.