Как вы управляете встроенными файлами конфигурации и библиотеками в веб-приложениях Java?

В настоящее время я работаю над проектом j2ee, который уже некоторое время находится в стадии бета-тестирования. Прямо сейчас мы просто решаем некоторые проблемы с процессом развертывания. В частности, в войну встроен ряд файлов (некоторые xml-файлы и .properties), которые требуют развертывания разных версий в зависимости от того, находитесь ли вы в среде разработки, тестирования или производственной среды. Такие вещи, как уровни журналов, пулы соединений и т. д.

Поэтому мне было интересно, как разработчики здесь структурируют свой процесс развертывания веб-приложений. Выгружаете ли вы как можно больше конфигурации на сервер приложений? Заменяете ли вы файлы настроек программно перед развертыванием? Выбрать версию в процессе сборки? Редактировать войны вручную?

Кроме того, как далеко вы идете в предоставлении зависимостей через статические библиотеки серверов приложений и сколько вы сами вкладываете в войну? Все это просто для того, чтобы получить некоторое представление о том, что является общепринятой (или, возможно, лучшей) практикой на данный момент.


person wds    schedule 24.02.2009    source источник


Ответы (5)


Я работаю в среде, где отдельная группа серверов выполняет настройку QA и рабочих серверов для наших приложений. Каждое приложение обычно развертывается на двух серверах в отделе контроля качества и на трех серверах в производственной среде. Моя команда разработчиков обнаружила, что лучше всего свести к минимуму количество настроек, требуемых на сервере, поместив как можно больше настроек в войну (или ухо). Это упрощает настройку сервера, а также сводит к минимуму вероятность того, что команда серверов неправильно настроит сервер.

У нас нет конфигурации для конкретной машины, но у нас есть конфигурация для конкретной среды (разработка, контроль качества и производство). У нас есть файлы конфигурации, хранящиеся в файле войны, которые названы по среде (например, dev.properties, qa.properties, prod.properties). Мы поместили свойство -D в командную строку Java виртуальной машины сервера, чтобы указать среду (например, java -Dapp.env=prod ...). Приложение может искать системное свойство app.env и использовать его для определения имени используемого файла свойств.

Я полагаю, что если у вас есть небольшое количество свойств, специфичных для машины, вы также можете указать их как свойства -D. Commons Configuration предоставляет простой способ объединения файлов свойств со свойствами системы.

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

person Bill.D    schedule 25.02.2009
comment
Большинство ответов говорят об одном и том же, принимая это, поскольку мы, вероятно, в конечном итоге сделаем что-то очень похожее. - person wds; 02.03.2009

Я думаю, что если свойства специфичны для машины/развертывания, то они принадлежат машине. Если я собираюсь подвести итоги войны, то она должна быть отключаемой, что не означает ничего конкретного для машины, на которой она работает. Эта идея сломается, если война будет иметь машинно-зависимые свойства.

Что мне нравится делать, так это создавать проект с файлом properties.example, у каждой машины есть .properties, который находится где-то, где война может получить к нему доступ.

Альтернативным способом было бы иметь муравьиные задачи, например. для dev-war, stage-war, prod-war и иметь наборы свойств как часть проекта, встроенные в war-build. Мне это не очень нравится, потому что вы в конечном итоге получите такие вещи, как расположение файлов на отдельном сервере, как часть сборки вашего проекта.

person Steve B.    schedule 24.02.2009

что касается файлов конфигурации, я думаю «>Ответ Стива пока лучший. Я бы добавил предложение сделать внешние файлы относительно пути установки файла войны - таким образом вы можете иметь несколько установок войны на одном сервере с разными конфигурациями.

например Если мой dev.war будет распакован в /opt/tomcat/webapps/dev, я буду использовать ServletContext.getRealPath, чтобы найти базовую папку и имя военной папки, чтобы файлы конфигурации жили в ../../config/dev относительно войны или /opt/tomcat/config/dev в абсолютном.

Я также согласен с Билл о том, чтобы помещать как можно меньше в эти внешние файлы конфигурации. Использование базы данных или JMX в зависимости от вашей среды для хранения столько, сколько это имеет смысл. Конфигурация Apache Commons имеет хороший объект для обработка конфигураций, поддерживаемых таблицей базы данных.

Что касается библиотек, я согласен с неизвестно, есть ли все библиотеки в папке WEB-INF/lib в файле войны (самоупакованные). Преимущество в том, что каждая установка приложения автономна, и у вас могут быть разные сборки войны, использующие разные версии библиотек одновременно.

Недостатком является то, что он будет использовать больше памяти, поскольку каждое веб-приложение будет иметь свою собственную копию классов, загружаемую собственным загрузчиком классов.

Если это представляет реальную проблему, вы можете поместить банки в общую папку библиотеки для вашего контейнера сервлета ($CATALINA_HOME/lib для tomcat). Однако все установки вашего веб-приложения, работающие на одном сервере, должны использовать одни и те же версии библиотек. (На самом деле это не совсем так, поскольку при необходимости вы можете поместить переопределяющие версии в отдельную папку WEB-INF/lib, но это становится довольно грязным в обслуживании.)

В этом случае я бы создал автоматический установщик для общих библиотек, используя InstallShield или NSIS или аналогичный для вашей операционной системы. система. Что-то, что может упростить определение того, есть ли у вас самый последний набор библиотек, а также обновление, понижение версии и т. д.

person Evan    schedule 25.02.2009

Я обычно делаю два файла свойств:

  • один для специфики приложения (сообщения, внутренние «магические» слова), встроенного в приложение,
  • другой для специфики среды (доступ к базе данных, уровни журналов и пути...), выставленный на пути к классам каждого сервера и "застрявший" (не поставляется с моим приложением). Обычно я «мавенизирую» или «антизую» их, чтобы указать конкретные значения, в зависимости от целевой среды.
  • Крутые ребята используют JMX для поддержания конфигурации своего приложения (конфигурация может быть изменена в реальном времени без повторного развертывания), но это слишком сложно для моих нужд.

Серверные (статические?) Библиотеки: я настоятельно не рекомендую использовать серверную библиотеку в своих приложениях, поскольку она добавляет зависимость от сервера:

  1. ИМО, мое приложение должно быть «самоупакованным»: отказаться от моей войны, и все. Я видел вары с 20 мегабайтами банок в нем, и это меня не беспокоит.
  2. Обычная передовая практика состоит в том, чтобы ограничить ваши внешние зависимости тем, что предлагается догмой J2EE: J2EE API (использование сервлетов, Ejbs, Jndi, JMX, JMS...). Ваше приложение должно быть "независимым от сервера".
  3. Размещение зависимостей в вашем приложении (war, ear, whatever) является самодокументируемым: вы знаете, от каких библиотек зависит ваше приложение. С серверными библиотеками вы должны четко документировать эти зависимости, поскольку они менее очевидны (и вскоре ваши разработчики забудут об этом маленьком волшебстве).
  4. Если вы обновите свой сервер приложений, шансы того, что серверная библиотека, от которой вы зависите, также изменится. Редакторы AppServer не должны поддерживать совместимость своих внутренних библиотек от версии к версии (и в большинстве случаев они этого не делают).
  5. Если вы используете широко используемую библиотеку, встроенную в ваш сервер приложений (на ум приходит журнал jakarta commons, также известный как jcl) и хотите обновить ее версию, чтобы получить новейшие функции, вы сильно рискуете, что ваш сервер приложений не будет ее поддерживать.
  6. Если вы полагаетесь на статический объект сервера (в статическом поле класса сервера, например, карту или журнал), вам придется перезагрузить сервер приложений, чтобы очистить этот объект. Вы теряете возможность горячего повторного развертывания вашего приложения (старый серверный объект все еще будет существовать между повторными развертываниями). Использование объектов уровня приложения (кроме тех, которые определены в J2EE) может привести к тонким ошибкам, особенно если этот объект является общим для нескольких приложений. Вот почему я настоятельно не рекомендую использовать объекты, которые находятся в статическом поле библиотеки appServer.

Если вам абсолютно необходим «этот объект в jar-файле этого сервера приложений», попробуйте скопировать jar-файл в свое приложение, надеясь, что нет никакой зависимости от jar-файла другого сервера, и проверьте политику загрузки классов вашего приложения (у меня есть привычка помещать «родительский последний» загрузку классов политика для всех моих приложений: я уверен, что меня не будут «загрязнять» серверные банки, но я не знаю, является ли это «лучшей практикой»).

person Tusc    schedule 25.02.2009

Я закинул все настройки в базу. Контейнер (Tomcat, WebSphere и т. д.) дает мне доступ к начальному соединению с базой данных, и с этого момента все выходит из базы данных. Это позволяет использовать несколько сред, кластеризацию и динамические изменения без простоев (или, по крайней мере, без повторного развертывания). Особенно приятно иметь возможность изменять уровень журнала на лету (хотя вам понадобится либо экран администратора, либо фоновое обновление, чтобы принять изменения). Очевидно, что это работает только для вещей, которые не требуются для запуска приложения, но в целом вы можете довольно быстро получить доступ к базе данных после запуска.

person Brian Deterling    schedule 24.02.2009