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):
Можно уложить этот код в меньшее количество строк, переписать в синтаксисе make или даже оформить как build.xml для ant.
Суть от этого не изменится. Корнем маппинга классов, хранящихся «россыпью» (то есть в виде неупакованных в jar-архивы файлов) является каталог _classes. Jar-библиотеки лежат в нем же (если накапливается много — можно разложить по подкаталогам). Уяснив и строго соблюдая данное правило, можно надежно избавиться от проблемы jar-hell.
В 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.
Комментарии (2)
RSS свернуть / развернутьнасчет принципа бритвы Оккама — я оказывается сам того не ведая все время пользуюсь этим принципом
Sergei_T
yababay
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.