3f-lab: каталог _classes (лекция 3)

Большинству программистов, причем вне зависимости от используемого языка, известна проблема, известная как "кошмар зависимостей". В мире Windows она называется dll-hell, в мире open source — как dependences hell, наконец, в Java это jar-hell. Что это за беда и как ее преодолевает 3f-lab?


В Java существует соглашение о пакетах (пространствах имен). Например, два человека, не подозревая о существовании друг друга, пишут классы с одинаковым названием — Element. Но один из них — химик и подразумевает химический элемент, а другой связан с кинематографом и подразумевает фильм «5-й элемент». Если бы не было пакетов, при попытке одновременного использования этих классов возникла бы путаница. Поэтому классы помещают в пакеты и в первом случае полное (с учетом пакета) имя класса могло бы выглядеть как ru.mendeleev.Element, а во втором — us.besson.Element.

Каждый, кто начинает писать программы на языке Java, должен придумать имя похитрее, с которого будут начинаться названия его пакетов. Рекомендуется использовать прочтенное в обратной последовательности имя своего веб-сайта, чтобы гарантировано отличаться от других. Когда я начинал программировать на Java создать веб-сайт с именем домена второго уровня было не таким уж простым и дешевым делом, поэтому я решил использовать заковыристое название com.michaelbelyakov1967 для своих пакетов (как если бы у меня был сайт с адресом michaelbelyakov1967.com). Трудно представить, что где-то в мире живет еще один Михаил Беляков 1967 года рождения, который додумался до такого же. Поэтому я считаю имена своих пакетов уникальными .

В рамках лаборатории 3f-lab, в соответствии с правилами маппинга пакетов, класс Element (название условное), принадлежащий пакету com.michaelbelyakov1967.util, должен храниться в рамках лаборатории в файле _classes/com/michaelbelyakov1967/util/Element.class. Так что внутри _classes нужно создать еще и соответствующие подкаталоги. Впрочем, если вы планируете пользоваться сборщиком ant, то особо задумываться о создании подкаталогов не надо: он сам создает недостающие во время сборки.

И все-таки, маппинг пакетов — недостаточное средство для решения проблемы jar-hell. Думаю, каждый java-программист хоть раз встречался с проблемой, когда он меняет код класса, а поведение программы не меняется. Можно потратить несколько часов на выяснение того простого обстоятельства, что java загружает не изменяемую, а какую-то старую версию класса, когда-то пару недель назад запакованную в архив, засунутый, в свою очередь, в $JAVA_HOME/jre/ext/lib «для удобства». Такие «удобства» оборачиваются порой потерей немалого количества нервных клеток.

Есть несколько «мест», откуда java загружает свой псевдокод для выполнения программ и «места» эти нужно знать. Исполняемый код может находиться:

1. в одном из каталогов, указанных в переменной CLASSPATH;
2. в jar-архиве, передаваемом интерпретатору ключом -jar;
3. в стандартном каталоге $JAVA_HOME/jre/lib/ext (туда можно поместить соответствующий jar-архив);
4. в случае сервлетов это еще и каталог WEB-INF/lib (в WEB-INF также могут быть размещены и незапакованные классы-файлы);
5. можно написать собственные загрузчики классов, еще более усугубив проблему jar-hell.

Порядок загрузки, в принципе, хорошо документирован. Но чтобы избавиться от лишней головной боли (бритва Оккама должна делать свое дело), я решил хранить классы (как в виде файлов, так и в виде архивов) в строго определенном месте — ~/.3f-lab/_classes. Часть java-библиотек (jar-архивов) программист получает в готовом виде, скачивая их из Интернета. Часть пишет сам и, поскольку самостоятельно написанный код меняется очень часто, собственные классы лучше хранить в незапакованном виде.

Предположим, я хочу откомпилировать класс com.michaelbelyakov1967.test.Test, который использует мой собственный ранее созданный класс com.michaelbelyakov1967.util.TuttiFrutti (хранится в соответствующем каталоге в незапакованном виде), а также библиотеку mailapi.jar (допустим, класс должен отправлять почту и я решил воспользоваться для этого готовым решением). Для этого в рамках 3f-lab нужно выполнить примерно такой bash-скрипт (находясь в каталоге ~/.3f-lab/_reusable/test и работая под Linux):

CLASSPATH=/_classes:/_classes/mailapi.jar 
JAVAC=/_bin/java/sun/bin/javac 
TARG=/_classes/com/michaelbelyakov1967/test 
mkdir -p $TARG 
$JAVAC Test.java 
mv *.class $TARG


Можно уложить этот код в меньшее количество строк, переписать в синтаксисе make или даже оформить как build.xml для ant.

<project name="Hello world" default="cmp">

 <target name="cmp">
  <javac srcdir="." destdir="/_classes"/>
 </target>

</project>


Суть от этого не изменится. Корнем маппинга классов, хранящихся «россыпью» (то есть в виде неупакованных в jar-архивы файлов) является каталог _classes. Jar-библиотеки лежат в нем же (если накапливается много — можно разложить по подкаталогам). Уяснив и строго соблюдая данное правило, можно надежно избавиться от проблемы jar-hell.
  • +3
  • 07 января 2010, 22:25
  • yababay

Комментарии (2)

RSS свернуть / развернуть
+
0
Спасибо за развернутый рассказ о классах и пространствах имен
насчет принципа бритвы Оккама — я оказывается сам того не ведая все время пользуюсь этим принципом
avatar

Sergei_T

  • 07 января 2010, 22:33
+
0
Видимо этот принцип заложен в любом живом существе. Иначе все бы уже умерли от болезни под названием «взрыв мозга» .
avatar

yababay

  • 08 января 2010, 01:30

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.