7 января 2011 в 19:54

Создание своих архетипов и каталогов в Maven из песочницы

Java*
Уже довольно продолжительное время (около года набежит) активно пользуюсь системой сборки Apache Maven и вполне ею доволен. Несмотря на свои очевидные и не очень недостатки, неоспоримым преимуществом является автоматическое управление зависимостями, хорошая структурированность проектов и отсутствие скриптов сборки как таковых, а следовательно проблем с ними.

Многим может не нравится, что мавен в самом деле отбирает у разработчика свободу выбора структуры проекта и прямо таки диктует ее, но в самом ли деле эта свобода настолько важна, чтобы делать изза нее жирный аргумент против? Не думаю. Есть другие, более серьезные, на мой взгляд, недостатки, в первую очередь — трудность диагностики проблем при сборке и недостаточная документированность мавена и плагинов.

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

Поиск плагинов и их настройка — это тоже мучительные круги ада, но по сравнению с xml-программированием на ant'e это еще ничего.

Однако при правильном подходе и набитом скилле, мавен практически не ощущается в работе, что мне очень нравится.

Собственно, в этой статье речь пойдет не о муках, а о архетипах, их каталогах и создании собственных архетипов и каталогов.
С помощью этих нехитрых концепций можно ощутимо упростить себе жизнь при создании нового проекта.

Создаем локальный каталог



Архетип в мавене — это шаблон нового проекта, со структурой и заготовками исходных и конфигурационных файлов.

Любой, кто хотя бы раз создавал проект на мавене, сталкивался с архетипами. Например, типичный метод создания проекта, который витает в интернете:

	mvn archetype:create                                    \
	  -DarchetypeGroupId=<archetype-groupId>                \
	  -DarchetypeArtifactId=<archetype-artifactId>          \
	  -DarchetypeVersion=<archetype-version>                \
	  -DgroupId=<my-groupid>                                \
	  -DartifactId=<my-artifactId>
	


Вопрос, откуда взять нужные параметры, всегда меня волновал, обычно я вежливо спрашиваю у Гугла и он мне обычно отвечает :)

Если мы например, захотим создать простоe приложение, то мы используем архетип под названием maven-archetype-quickstart, например вот так:

	mvn archetype:create                                    \
	  -DarchetypeGroupId=org.apache.maven.archetypes        \
	  -DarchetypeArtifactId=maven-archetype-quickstart      \
	  -DarchetypeVersion=1.0                                \
	  -DgroupId=org.example                                 \
	  -DartifactId=simpleapp
	

Есть более удобный способ создания проекта, с помощью цели archetype:generate. При вызове, в интерактивном режиме будет предложено ввести параметры нового проекта.

mvn archetype:generate


Но тут возникает проблема. Мавен предлагает выбрать тип нового проекта из списка готовых шаблонов, а список состоит ни много ни мало из более чем 300 вариантов. Найти там нужный шаблон — задача довольно нетривиальная, обычно я сбрасываю вывод в файл и потом грепом ищу то что нужно.

Погуглив немного, я нашел для себя решение этой проблемы, не совсем как по мне окончательное, но вполне себе с намеком на элегантность. Архетипы можно обьединять в каталоги! Но как это может помочь?

Каталог определяется URL'ом, где он расположен, кроме того в мавене есть три предопределенных каталога, или если хотите, алиаса: internal, remote и local.

internal содержит архетипы, встроенные в maven, их немного и они уже де-факто идут с самим дистрибутивом
remote центральный каталог maven, находится по адресу http://repo1.maven.org/maven2/archetype-catalog.xml, его местоположение зависит от текущих настроек мавена, например возможно переопределить этот урл на одно из зеркал репозитория
local каталог из локального репозитория, обычно находится в ~/.m2/archetype-catalog.xml


У цели archetype:generate есть параметр archetypeCatalog, с помощью которого можно указать список каталогов, где нужно искать возможные архетипы. По умолчанию, значение параметра 'remote,local'. Но если убрать оттуда remote, то получим почти то, что нужно.

Например, вот так:

	grim@blackbox:~/projects$ mvn archetype:generate -DarchetypeCatalog=local

	[ ...булшит... ]

	Choose archetype:
	1: local -> maven-archetype-quickstart (quickstart)
	2: local -> maven-archetype-archetype (archetype)
	3: local -> maven-archetype-webapp (webapp)
	Choose a number: 1:
	


Подсмотреть структуру файла можно из каталога remote. Например, чтобы получить список выше, файл должен иметь вид

	<?xml version="1.0" encoding="UTF-8"?>
	<archetype-catalog xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0 http://maven.apache.org/xsd/archetype-catalog-1.0.0.xsd"
	    xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0"
	    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	  <archetypes>
	    <archetype>
	      <groupId>org.apache.maven.archetypes</groupId>
	      <artifactId>maven-archetype-quickstart</artifactId>
	      <version>1.1</version>
	      <description>quickstart</description>
	    </archetype>
	    <archetype>
	      <groupId>org.apache.maven.archetypes</groupId>
	      <artifactId>maven-archetype-archetype</artifactId>
	      <version>1.0</version>
	      <description>archetype</description>
	    </archetype>
	    <archetype>
	      <groupId>org.apache.maven.archetypes</groupId>
	      <artifactId>maven-archetype-webapp</artifactId>
	      <version>1.0</version>
	      <description>webapp</description>
	    </archetype>
	  </archetypes>
	</archetype-catalog>
	


Немного поколдовав с конфигурацией мавена, можно сделать такую ситуацию постоянной, нужно создать профиль, в котором выставить значение переменной archetypeCatalog. Для этого в ваш файл settings.xml нужно добавить

	  <profiles>

	    <profile>
	        <id>dev</id>
	        <activation>
	            <activeByDefault>true</activeByDefault>
	        </activation>
	        <properties>
	           <archetypeCatalog>local</archetypeCatalog>
	        </properties>
	    </profile>

	  </profiles>
	


Усе! Теперь, при вызове, цель archetype:generate вместо тонн мусора, будет выводить вам то, что скажете.

К слову у плагина archetype есть любопытная цель crawl, которая сканирует ваш локальный репозиторий на предмет наличия архетипов и генерирует из всех найденных каталог. К сожалению, документация немного врет и по умолчанию файл генерируется совсем не там где ожидает увидеть его мавен. Готовить нужно так:

	grim@blackbox:~/projects$ mvn archetype:crawl -Dcatalog=~/.m2/archetype-catalog.xml
	

Вопреки официальной документации параметр называется не catalogFile, а catalog.

Создаем свой архетип



Вторая проблема, которую мы рассмотрим — это создание собственного архетипа. Зачем это нужно? Нужно это по той простой причине, что при всем кажущемся обилии архетипов, среди них не оказалось подходящего для простой веб-разработки. Есть несколько близких по духу, например тот же maven-archetype-webapp, но дескрипторы в нем устаревшие, нету log4j и нормального темплейта jsp. В итогое после создания пустого проекта, нужно перейти в режим работы напильником, и с помощью гугла переделывать все как надо. В конце концов на десятый раз мне это надоело, и я решил создать свой собственный архетип, самый лучший и самый правильный. Более конкретно, создадим заготовку для простенького приложения на spring-mvc c использованием Servlet 2.5/JSP 2.1/JSTL 1.2 c готовым к работе логированием.

Внимание, в следующем абзаце возможно зависание от количества упоминаний слова архетип.

Для начала нужно создать проект для нашего архетипа, используя архетип maven-archetype-archetype, например с помощью того же archetype: сreate.

	grim@blackbox:~/projects$ mvn archetype:create      \
	   -DarchetypeArtifactId=maven-archetype-archetype  \
	   -DartifactId=baremvc                             \
	   -DgroupId=example
	

Чтобы не мучится в консоли, пересядем в эклипс, хотя конечно же все, что написано ниже, можно сделать и с помощью vim'а или еще чегото такого.

	grim@blackbox:~/projects$ cd baremvc && mvn eclipe:eclipse
	

После чего делаем импорт и смотрим на структуру более детально.



Проект состоит из одной папки resources, в которой содержися две подпапки: archetype-resources и META-INF. В первой храниться костяк будущих выдающихся проектов, которые еще будут созданы поколениями програмистов после нашей смерти, во второй хранится файлик META-INF/maven/archetype.xml. Это дескриптор архетипа. В нем будет хранится описание того, что входит в архетип.

Дополним костяк, всем чем нужно: добавим туда простенькую jsp страничку, более-менее сносный web.xml, простенький контроллер и конфиг log4j.properties. Все это вы найдете в архиве, который можно скачать. Из интересных моментов, на которые стоит обратить внимание, это замены, которые делает мавен при создании проекта. В архетипе реализован механизм темплейтов на основе Velocity, который практически не документирован, если ктото уверен в обратном, поделитесь, буду благодарен.

В частности в контроллере через темплейты реализована подстановка имени пакета.

	// HomeController.java
	package $package;

	import org.apache.commons.logging.Log;

	@Controller
	public class HomeController {

	...
	

Тот же самый ход использован в конфигурации Spring MVC и при генерации целевого pom.xml. Пока что список известных мне переменных довольно скуден: $groupId, $artifactId, $version и $package. Думаю, всем понятно, что каждый значит, все это указывается при создании проекта из архетипа.

Вообще тема темплейтов интересная и нераскрытая, думаю немного погодя раскопаю ее поглубже, а пока то что есть, вполне достаточно для наших скромных нужд.

Когда процесс подготовки шаблонов завершен, нужно подготовить файл-дескриптор архетипа, тот самый archetype.xml.

	<archetype xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	  xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype/1.0.0 http://maven.apache.org/xsd/archetype-1.0.0.xsd">

	  <id>baremvc</id>
	  <sources>
	    <source>src/main/java/HomeController.java</source>
	  </sources>
	  <resources>
	      <resource>src/main/resources/log4j.properties</resource>
	      <resource>src/main/webapp/home.jsp</resource>
	      <resource>src/main/webapp/WEB-INF/applicationContext.xml</resource>
	      <resource>src/main/webapp/WEB-INF/web.xml</resource>
	  </resources>
	  <testSources />
	</archetype>   
	

Тэг должен совпадать с artifactId нашего архетипа. Тэги <sources> и <resources> прдназначены для темплейтов разных частей архетипа. В частности ресурсы из папки webapp нужно указывать в тэге <resources>. Есть еще несколько допустимых секций. Ниже перечислены допустимые секции и папки, куда уйдут указанные в них шаблоны.

<sources> src/main/java
<resources> src/main/resources
<testSources> src/test/java
<testResources> src/test/resources
<siteResources> src/site


После того как все готово, можно установить наш архетип в репозиторий с помощью

	grim@blackbox:~/projects/baremvc$ mvn clean install
	

и теперь он готов к использованию.

	grim@blackbox:~/projects/baremvc$ cd ..
	grim@blackbox:~/projects$ mvn archetype:create          \
	  -DarchetypeGroupId=org.example                        \
	  -DarchetypeArtifactId=baremvc                         \
	  -DarchetypeVersion=1.0                                \
	  -DgroupId=org.example                                 \
	  -DartifactId=baremvcapp
	

Наш маленький проект готов к запуску

	grim@blackbox:~/projects/baremvcapp$ cd baremvcapp
	grim@blackbox:~/projects/baremvcapp$ mvn tomcat:run
	


После чего по ссылке http://localhost:8080/baremvcapp можно узреть сие творение.

Теперь архетип, можно сказать приготовлен, добавим его в локальный каталог руками или с помощью цели archetype:crawl.

	grim@blackbox:~/projects$ mvn archetype:crawl -Dcatalog=/home/grim/.m2/archetype-catalog.xml
	

Теперь при вызове archetype:generate в списке должна появиться строчка

	1: local -> baremvc (baremvc)
	

с чем я нас и поздравляю.

В заключение осталось добавить, что описанный выше способ устарел (увы), и помечен как deprecated, но все еще работает, а про right way документации как то кот наплакал. Все что мне пока известно, это что дескриптор изменили, теперь он называется archetype-metadata.xml и имеет более мощный синтаксис. Надеюсь хватит еще на десяток лет вперед статьи писать.

Архив, который можно скачать

Исходники, которые можно посмотреть

Использованные ресурсы


  1. Guide to Creating Archetypes — http://maven.apache.org/plugins/maven-archetype-plugin-1.0-alpha-7/examples/archetype.html
  2. Maven Archetype Plugin — http://maven.apache.org/archetype/maven-archetype-plugin/
  3. Maven – размышления после двух лет использования — http://habrahabr.ru/blogs/personal/102181/


UPD: Есть еще цель archetype:create-from-project, которая сгенерирует шаблон из вашего проекта. Шаблон сгенерируется в папку target/generated-sources/archetype. То есть фактически из любого вашего проекта можно сгенерировать архетип и потом использовать его в качестве отправной точки. Спасибо 1nd1go
Алексей Хилькевич @1ex
карма
31,7
рейтинг 0,0
Похожие публикации

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

  • 0
    Недавно столкнулся с Мавеном и он отпугнул меня. Вы в самом начале пишете, что Мавен навязывает структуру проекта, но это не наибольшая проблема. Я с этой проблемой до сих пор уживаюсь с большим зубовным скрежетом (: Отчасти потому, что мавеновская структура проекта делает очень не удобной работу в Eclipse, потому что у него стандартная структура проекта сильно отличается. У Вас скрины из Eclipse. Вот теперь, собственно, вопрос: как вы подружили Maven и Eclipse?
    PS я пробовал плагины для интеграции, но это не решает многих проблем. К примеру, если создавать в Eclipse Dynamic Web-project то вообще случается беда и совершенно не понятно как подружить структуры.
    Простите за вопрос несколько не по теме. Заранее спасибо за ответ
    • 0
      C Dynamic Web приложениями там действительно по умолчанию генерируется невразумительный проект, поскольку по умолчанию мавен не ориентируется на WTP и не генерирует его подержку. Чтобы включить WTP нужно выставить параметр wtpversion в значение 2.0 (по умолчанию none) через командную строку или в конфигуреции мавена

      mvn eclipse:eclipse -Dwtpversion=2.0

      сгенерирует поддержку wtp в проекте, но на картинке этой поддержки нету, поскольку это не есть веб-проект.

      Что до разных структур, мавен генерирует для eclipse папки для быстрого перехода к исходникам, ресурсам и тестам. Чего нету так это такой же папочки для src/main/webapp, аля WebContent, это действительно напрягает. Можно попытаться прикрутить самостоятельно
    • +2
      Ну не знаю, в том же Эклипс я просто обожаю мавен. Да, проблемы с фейсетами, но нужны ли они… Мне, например, нет. Для мавена есть куча плагинов и поддерживать, дебажить, ранить тоже веб приложение в томкате/джейбоссе это совершенно тривиальное дело. А то что мевен навязывает свою структуру, это же просто огромный плюсище. И мне очень приятно осознавать то, что я могу сейчас взять и поменять свою IDE не особо вникая в какие-то там нюансы с миграцией и особенности IDE. Блин, а найти и добавить зависимость с помощью m2eclipse, ну это же просто кайфище… Просто, как раз-два… Эх, поработать бы Вам немного в разношерстной команде и вы бы поняли все прелести мавена.
      • 0
        ну кстати, несколько раз таки пересаживался с eclipse на idea и обратно без особых проволочек, а в особо тяжелых случаях, так как мы на виртуалках работаем, вообще работал в текстовом редакторе )
        • 0
          Кстати, спасибо за статью. Чудесно проделанная работа. Никогда не задумывался над созданием собственных архетипов. Видать не так часто приходится проекты создавать)
    • 0
      Как подсказали знающие люди (unkind и по электропочте), есть плагин для eclipse m2eclipse, который поддерживает человеческий импорт проектов и удобный поиск зависимостей, Сам долго ковырял его, не мог заставить работать, оказывается нужно ставить и extras тоже, без него многие фишки не работают, включая поиcк зависимостей.

      Сходите на сюда, установите плагин и дополнения к нему (из extras) и попробуйте, надеюсь, будете приятно удивлены.
      • 0
        спасибо. я его пробовал. на сколько мне хватило прямости рук — он не решает проблему с веб-проектом ):
        • 0
          ну не знаю, он мне даже папочку для webapp создал, на которую я выше жаловался, клево в общем, я уж думал что до смерти буду по уровням ходить
  • +3
    Отсутствие свободы в структуре проекта это жирнейший плюс мавена. Такие проекты, как мавен, ведут индустрию разработки ПО от «ремесленничества» к «промышленному производству».
    • 0
      Во многом согласен.
      Но это скорее обусловлено тем, что среднестатистический программист не знает о паттернах организации структуры проекта.
      В значительном количестве случаев преимущества Maven'а не используются, естественно при наличии хорошей команды.
  • 0
    У меня тут есть такая задача, надо часть DAO одного проекта использовать в другом. Каким бы образом мне это в maven описать или как это там можно сделать?
    • +1
      создаете отдельный maven-проект с типом jar, делаете install в репозиторий (ваш локальный или локальный для вашего проекта — например сервер nexus), потом в нужном вам проекте прописываете dependency на созданный вами jar.
      • 0
        У меня уже проект то есть, я думаю создать отдельную цель для сборки jar и дальше уже в репозиторий и использовать.
        • +1
          если я правильно понимаю, то это будет не совсем true-way. Вам надо одинаковые DAO из обоих проектов вынести в отдельный проект с packaging jar и прописать dependencies на него в этих проектах. У вас получается правильная структура. Потом ее будет также проще подключить в тот же continuous integration
  • +2
    для создания архетайпа можно пойти более простым путем с помощью mvn archetype:create-from-project — т.е. вы создаете пустой проект с нужной вам структурой, настройками и т.п., потом выполняете этот goal и получаете созданый в нужном виде архетайп.

    Подробнее тут: maven.apache.org/archetype/maven-archetype-plugin/advanced-usage.html и maven.apache.org/archetype/maven-archetype-plugin/create-from-project-mojo.html
    • 0
      В общем да, но это все равно что использовать сгенерированные приложения — вроде работает, а непонятно как. Мне хотелось как раз разобраться как оно работает. Хотя про него сказать все же стоит, добавил в статью
  • 0
    Спасибо тебе за статью )

    Мне мавен как раз и понравился тем, что в нём навязывается структура проекта.

    Так как в этом случае остаётся выбрать архетип от компетентного автора, и ваять приложение с правильной архитектурой.

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