Pull to refresh

Ant+Tomcat: небольшая автоматизация рутины

Reading time6 min
Views13K
День добрый всем. Решил написать заметку о небольших средствах автоматизации, которые возникли в процессе моей работы со связкой Ant+Tomcat. Работаю java-разработчиком, с недавних пор пришлось окунуться в web-разработку на Java (надо сказать не без удовольствия). Никогда с серьезными проектами для web на java не сталкивался, игрался пару раз с примерами в рамках книжек по java из серии «обо всем по немного», но ничего серьезного. А здесь проект из полноценного портала с backend`ом для отвественных за контент, большими объемами данных в БД. Ну что же столкнулся да и столкнулся. Работа пошла, новая область знаний — интересно, мелочи не достают. Но со временем процесс сборки и развертывания приложения стал очень сильно доставать, так как в самые «жаркие» дни приходилось выполнять эту операцию раз по 40, чтобы посмотреть результат работы и прощелкать его. Вот тут и возник вопрос, нельзя ли это как то автоматизировать.

Для тех кто так же как и я раньше не особо представляет процесс сборки и развертывания web-приложений на Java распишу чуток подробнее.

1. Итак, приложение необходимо собрать. Это можно сделать и через IDE, но на больших проектах, где несколько разработчиков и у каждого может быть свой IDE лучше использовать ANT — универсально и удобно. Итак делаем сборку, например так: ant jar. У меня сборка одного модуля jar в нашем проекте в среднем занимает секунд 15-20. Само web-приложение представляет собой war-файл (аналог jar файла в Java SE). Но конечный war-файл может иметь (и как правило имеет) несколько зависимостей от jar-файлов других модулей. Соотвественно, если изменился код модуля, от которого зависит конечный war-файл, то сначала пересобираем модуль, потом собираем само приложение. У нас таких модулей 2, как правило в процессе работы изменения идут в пределах одного модуля, хотя бывает, что необходимо пересобрать оба модуля или ничего не надо пересобирать (кроме конечного war, в коде которого что-то изменилось). В общем, как правило пересобирается 1 модуль. Поэтому последовательность команд такая будет:

cd {директория модуля}
ant jar
cd {директория конечного приложения}
ant war

В итоге получим war-файл приложения. На сборку с учетом переключений между директориями уходит 50-60 секунд. Сразу скажу, что в проекте конечных war-файлов два: публичная часть и закрытая часть, и для общей сборки есть само собой своя команда, но ее неудобство в том, что происходит сборка «ненужного» сейчас war — что тоже время.

2. Для того, чтобы увидеть само приложение в деле, полученный war-файл необходимо развернуть на сервере. Для этого через браузер заходим в панель управления Tomcat, удаляем старую версию приложения (если оно было), указываем расположение нового war-файла и ждем некоторое время (40-60 секунд), после этого можем начинать «щупать» созданное приложение.

Я не зря пишу примерное время сборки и развертывания приложения — в сумме эти два на первый взгляд простых шага занимают 2-3 минуты. Вроде немного, но при частых изменениях или поиске решения какого-то бага приходится снова и снова пересобирать проект, делать undeploy (удаление) старой версии приложения с сервера, а потом deploy (развертывание) новой версии приложения. Бывает что за день повторяешь эту операцию считанные разы, а бывает, как писал выше, повторы этой операции происходят десятками раз. В итоге само собой возник вопрос об оптимизации данного процесса, т.к. повтор этой операции 10-20 раз ведет к затратам в 30-60 минут. Ладно б если в это время можно было отвлечься от компьютера, а получается, что необходимо плотное участие человека.

Сначала возникла идея в ant добавить одну команду для выполнения шага №1 (отдельно по каждому war), но потом возник вопрос «можно ли автоматизировать шаг №2?», то есть научить ant управлять развертыванием приложения на tomcat. Немного поискав в гугле, нашел несколько решений из которых собрал свое, взяв из каждого какие то моменты.

Процесс сборки приложения в ant я опущу, так как это описано в любом справочном материале по этой утилите, к тому же это специфично для каждого отдельного проекта. Сразу перейду к решению шага №2.

Прежде всего необходимо узнать есть ли в системе tomcat, чтобы было с чем работать:

    <target name="if-has-tomcat">
      <property environment="env"/>
      <condition property="has.tomcat">
	<available file="${env.CATALINA_HOME}"/>
      </condition>
    </target>

Создаем задачу «if-has-tomcat», суть которой в том, чтобы проверить доступность директории указанной в системной переменной CATALINA_HOME и результат этой проверки представить в виде переменной «has.tomcat». Выражение property environment="env" как раз позволяет получить доступ к системным переменным.

Теперь когда мы знаем, что tomcat есть в системе, можно подключать его библиотеки, которые позволят управлять tomcat из ant. Заодно здесь же проверим, есть ли старая версия war-файла на сервере.

    <target name="check-if-deployed" depends="if-has-tomcat" if="has.tomcat">
      
      <property name="tomcat.home.dir" location="${env.CATALINA_HOME}" />
      <property name="tomcat.base.url" value="http://localhost:8080" />
      <property name="tomcat.manager.url" value="${tomcat.base.url}/manager/text" />
      <property name="tomcat.user.name" value="login" />
      <property name="tomcat.user.password" value="password" />
      
      <condition property="is.webapp.deployed">
	<http url="${tomcat.base.url}/${ant.project.name}" />
      </condition>
      
      <path id="tomcat.classpath">
	<!-- We need the Catalina jars for Tomcat -->
	<fileset dir="${tomcat.home.dir}/lib">
	  <include name="catalina-ant.jar"/>
	  <include name="tomcat-coyote.jar"/>
	  <include name="tomcat-util.jar"/>
	</fileset>
	<fileset dir="${tomcat.home.dir}/bin">
	  <include name="tomcat-juli.jar"/>
	</fileset>
      </path>

	<!-- Configure the custom Ant tasks for the Manager application -->
      <taskdef name="deploy"    classname="org.apache.catalina.ant.DeployTask" classpathref="tomcat.classpath"/>
      <taskdef name="list"      classname="org.apache.catalina.ant.ListTask" classpathref="tomcat.classpath"/>
      <taskdef name="reload"    classname="org.apache.catalina.ant.ReloadTask" classpathref="tomcat.classpath"/>
      <taskdef name="findleaks" classname="org.apache.catalina.ant.FindLeaksTask" classpathref="tomcat.classpath"/>
      <taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask" classpathref="tomcat.classpath"/>
      <taskdef name="start"     classname="org.apache.catalina.ant.StartTask" classpathref="tomcat.classpath"/>
      <taskdef name="stop"      classname="org.apache.catalina.ant.StopTask" classpathref="tomcat.classpath"/>
      <taskdef name="undeploy"  classname="org.apache.catalina.ant.UndeployTask" classpathref="tomcat.classpath"/>
    </target>

Сначала объявляем необходимые переменные для работы с tomcat: домашнюю папку tomcat, URL tomcat, URL менеджера, логин и пароль. Затем создаем условие, которое проверяет, размещено ли уже приложение (то есть перед тем разворачивать новую версию приложения необходимо будет старую удалить). Здесь ${ant.project.name} содержит название приложения, которое объявляется выше (я объявил в шапке скрипта ant, т.к. эта переменная участвует в тасках по сборке проекта). Следующий шаг — подключение библиотек, которые позволят управлять сервером через ant. Ну и последнее — объявляем таски для ant для управления tomcat.

Теперь когда мы знаем все исходные данные, можно удалять старую версию war-файла (если она есть) — команда undeploy и разворачивать новый war-файл — команда deploy.

    <target name="undeploy" depends="if-has-tomcat, check-if-deployed" if="is.webapp.deployed">
      <!-- TOMCAT undeploy-->
	<undeploy
	  url="${tomcat.manager.url}"
	  username="${tomcat.user.name}"
	  password="${tomcat.user.password}"
	  path="/${ant.project.name}"
	  />
    </target>
		
    <target name="deploy" depends="clean, war, if-has-tomcat, undeploy" if="has.tomcat">
	<!-- TOMCAT deploy-->
	<deploy
	  url="${tomcat.manager.url}"
	  username="${tomcat.user.name}"
	  password="${tomcat.user.password}"
	  path="/${ant.project.name}"
	  war="${dist.dir}/${ant.project.name}.war"
	  />
    </target>

Здесь по большому счету ничего сложно. Всегда используются команда ant deploy, которая выполняет очистку всех папок с class файлами (clean), потом выполняется сборка war-файла(war), потом выполняется проверка наличия tomcat (if-has-tomcat), затем при положительном исходе предыдущей проверки выполняется таска undeploy, которая проверяет наличие старой версии war-файла на сервере и при необходимости удаляет его, ну и в последнюю очередь выполняется непосредственно развертывание приложения на сервере. Свойство war в таске deploy, как раз указывает где расположен новый war файл.

В таске undeploy, как видно так же, как и в deploy выполняется проверка на наличие tomcat в системе. Сделано это для того, чтобы можно было безопасно выполнять команду ant undeploy.

В итоге, получилось, что все выполняется одной командой — ant deploy. Дальше можно на 1-2 минуты отвлечься — ant сделает все сам. Чисто время сборки и развертывания осталось тем же, а вот экономия в этом проекте на «ручном» щелканьи и вбивании нескольких команд составила 1-1,5 минуты с каждого deploy. Что за день выходит в 20-30 лишних минут и что самое главное: deploy выполняется с помощью одной команды и не требует к себе внимания, то есть во время сборки и развертывания можно слегка отвлечься и расслабиться.
Tags:
Hubs:
Total votes 7: ↑6 and ↓1+5
Comments13

Articles