четверг, 19 февраля 2009 г.

Сборка приложения используя maven-assembly-plugin с модулями Spring

Столкнулся с проблемой сборки приложения при помощи maven-assembly-plugin. Напомню, что этот плагин предназначен для создания архива, включающего в себя в распакованном виде какие-либо ресурсы, а также классы из зависимостей проекта. То есть, если вам нужно поместить приложение со всеми его зависимыми классами из других библиотек в один jar-файл, то этот инструмент может вам помочь.

Однако по причине того, что плагин распаковывает все зависимости в один каталог, могу возникнуть проблемы с библиотеками, имеющими файлы с одинаковыми названиями. Именно такая ситуация и происходит, когда пытаешься собрать приложение в один jar имеющее в зависимостях spring библиотеки. После запуска приложения возникает такая ошибка:

Exception in thread "main" java.lang.IllegalStateException: 
org.springframework.beans.factory.parsing.BeanDefinitionParsingException:
Configuration problem: Failed to import bean definitions
from URL location [classpath:/spring/dao-context.xml]
Caused by:
org.springframework.beans.factory.parsing.BeanDefinitionParsingException:
Configuration problem: Unable to locate Spring NamespaceHandler for
XML schema namespace [http://www.springframework.org/schema/tx]
Offending resource: class path resource [spring/dao-context.xml]

at org.springframework.beans.factory.parsing.
FailFastProblemReporter.error(FailFastProblemReporter.java:68)

Возникает она из-за того, что spring не может найти соответствующий NamespaceHandler предназначенный для обработки xml-схемы http://www.springframework.org/schema/tx. Соответствие между NamespaceHandler-ми и xml-схемами описывается в файле spring.handlers. Файл spring.handlers имеется в нескольких библиотеках spring (spring-aop.jar, spring-beans.jar...) в папке META-INF, таким образом в наш jar попадает лишь какой-то определенный экземпляр.При дублировании файлов maven-assembly-plugin в результате оставляет первый из них, merge-ить их он не умеет. Та же ситуация происходит и с файлом spring.schemas, в котором описываются соотвествия путей к xsd описаниям xml-схем и их реальным положением внутри библиотеки spring.

Решить возникшую проблему можно создав файлы spring.schemas и spring.handlers в папке /src/main/resources/META-INF вашего maven-проекта, агрегирующих в себе содержимое одноименных файлов из библиотек. В файле настройки maven-assembly-plugin-а необходимо указать папку /src/main/resources/META-INF которую мы будем копировать в архив, с помощью тэгов fileSets:

<assembly>
<id>with-dependencies</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${basedir}/src/main/resources/META-INF</directory>
<outputDirectory>META-INF</outputDirectory>
</fileSet>
</fileSets>

<dependencySets>
<dependencySet>
<outputDirectory/>
<outputFileNameMapping/>
<unpack>true</unpack>
</dependencySet>
</dependencySets>
</assembly>

Таким образом наши файлы попадут в архив первыми и уже не будут перезаписаны другими вариантами из библиотек Spring.

Кстати, версию maven-assembly-plugin-а следует использовать 2.2-beta-3 и старше. Предыдующая версия будет копировать все одинаковые файлы в ваш jar, и в одной папке будет несколько файлов с одним именем.

8 комментариев:

Satellite13 комментирует...

А зачем бы это могло понадобится?

Satellite13 комментирует...

Да к стати, у мя тоже есть блог но пишу я туда редко :)
http://jb-one.blogspot.com/

Никита Кокшаров комментирует...

Как я уже сказал, это может понадобиться для сборки приложения использующего Spring-контекст в единый jar.

Анонимный комментирует...

А чем отдельные джарники не угодили?

Андрей комментирует...

значит нужно

CorWin комментирует...

2Satellite13, Aноним, самый простой пример -- нужно сделать так называемый executable jar. можно подключить dependecy в качестве внешних библиотек, но... вместо одного jar'а будет N, что совершенно не удобно

Michael Tkachev комментирует...

Спасибо, то что нужно.

Анонимный комментирует...

Огромное спасибо! думал с ума сойду, пока решу эту проблему.