Как вы управляете встроенными конфигурационными файлами и библиотеками в java webapps?
В настоящее время я работаю над проектом j2ee, который был в бета-версии на некоторое время. Сейчас мы просто избиваем некоторые проблемы с процессом развертывания. В частности, существует множество файлов, встроенных в войну (некоторые xml файлы и .properties), которые требуют развертывания разных версий в зависимости от того, находитесь ли вы в среде разработчика, тестирования или производства. Такие вещи, как loglevels, пулы соединений и т.д.
Поэтому мне было интересно, как разработчики здесь структурируют свой процесс для развертывания webapps. Вы разгружаете как можно больше конфигурации на сервер приложений? Вы программно заменяете файлы настроек перед развертыванием? Выберите версию во время процесса сборки? Вручную редактировать войны?
Также, как далеко вы занимаетесь предоставлением зависимостей через статические библиотеки серверов приложений и сколько вы сами вкладываете в войну? Все это просто для того, чтобы получить представление о том, какова общая (или, возможно, лучшая) практика на данный момент.
Ответы
Ответ 1
Я работаю в среде, где отдельная команда сервера выполняет конфигурацию серверов контроля качества и производства для наших приложений. Каждое приложение обычно развертывается на двух серверах в QA и трех серверах в Production. Моя команда разработчиков обнаружила, что лучше всего минимизировать требуемую конфигурацию на сервере, поставив как можно большую конфигурацию в войне (или ухе). Это упрощает настройку сервера и минимизирует вероятность того, что команда сервера неправильно настроит сервер.
У нас нет конфигурации, специфичной для машины, но у нас есть конфигурация, специфичная для среды (Dev, QA и Production). У нас есть файлы конфигурации, хранящиеся в военном файле, которые называются средой (например, dev.properties, qa.properties, prod.properties). Мы помещаем свойство -D в командную строку VM Java сервера, чтобы указать среду (например, java -Dapp.env = prod...). Приложение может искать системное свойство app.env и использовать его для определения имени используемого файла свойств.
Я полагаю, что если у вас есть небольшое количество свойств, специфичных для машины, вы можете указать их как свойства -D. Commons Configuration предоставляет простой способ объединить файлы свойств с системными свойствами.
Мы настраиваем пулы соединений на сервере. Мы называем пул соединений одинаковым для каждой среды и просто указываем серверы, которые назначены каждой среде в соответствующую базу данных. Приложение должно знать только одно имя пула соединений.
Ответ 2
Я думаю, что если свойства специфичны для машины/развертывания, то они принадлежат на машине. Если я собираюсь обернуть вещи в войне, она должна быть отключена, что не означает ничего конкретного для машины, на которой она работает. Эта идея сломается, если в войне есть свойства, зависящие от машины.
Мне нравится создавать проект с файлом properties.example, каждая машина имеет .properties, которая живет где-то, когда война может получить к ней доступ.
Альтернативным способом было бы иметь задачи ant, например. для дев-войны, на этапе войны, войны и имеют комплекты свойств, входящих в проект, запеченные в войне. Мне это не очень нравится, потому что у вас в результате будут созданы такие вещи, как расположение файлов на отдельном сервере.
Ответ 3
wrt конфигурационные файлы, я думаю, ответ от Steve является лучшим. Я бы добавил предложение сделать внешние файлы относительно пути установки военного файла - таким образом, вы можете иметь несколько установок войны на одном сервере с различными конфигурациями.
например. Если мой dev.war
распаковывается в /opt/tomcat/webapps/dev
, я бы использовал ServletContext.getRealPath
, чтобы найти имя базовой папки и название военной папки, поэтому то файлы конфигурации будут жить в ../../config/dev
относительно войны или /opt/tomcat/config/dev
для абсолютного.
Я также согласен с Bill о том, чтобы как можно меньше в этих внешних файлах конфигурации. Использование базы данных или JMX в зависимости от вашей среды для хранения, насколько это имеет смысл. Конфигурация Apache Commons имеет хороший объект для обработки конфигураций, поддерживаемых таблицей базы данных.
Что касается библиотек, я согласен с неизвестным, чтобы иметь все библиотеки lib в папке WEB-INF/lib
в военном файле (самораспаковывающийся). Преимущество состоит в том, что каждая установка приложения является автономной, и вы можете иметь разные сборки войны, используя разные версии библиотек одновременно.
Недостатком является то, что он будет использовать больше памяти, поскольку каждое веб-приложение будет иметь свою собственную копию классов, загружаемых собственным загрузчиком классов.
Если это представляет серьезную проблему, вы можете поместить банки в общую папку библиотеки для своего контейнера сервлета ($CATALINA_HOME/lib
для tomcat). Однако все установки вашего веб-приложения, работающие на одном сервере, должны использовать одни и те же версии библиотек. (На самом деле, это не строго верно, поскольку вы можете поместить переопределяющие версии в отдельную папку WEB-INF/lib
, если это необходимо, но это становится довольно грязным для поддержки.)
В этом случае я бы построил автоматический установщик для общих библиотек, используя InstallShield или NSIS или эквивалент для вашей операционной системы. Что-то, что позволяет легко определить, есть ли у вас самый современный набор библиотек, а также обновить, понизить и т.д.
Ответ 4
Обычно я делаю два файла свойств:
- один для особенностей приложения (сообщения, внутренние "волшебные" слова), встроенные в приложение,
- другой для спецификаций среды (доступ к db, уровни журналов и пути...), которые отображаются на каждом пути класса сервера и "прикреплены" (не доставлены вместе с моим приложением). Обычно я "mavenise" или "anttise", чтобы добавить конкретные значения в зависимости от целевого env.
- Прохладные ребята используют JMX для поддержки своего приложения conf (conf может быть изменен в реальном времени, без повторного развертывания), но он слишком сложный для моих нужд.
Серверные (статические?) библиотеки: я сильно препятствую использованию библиотеки серверов в моих приложениях, поскольку она добавляет зависимость от сервера:
- IMO, мое приложение должно быть "самораспаковано": отбросить мою войну и все. Я видел войны с 20 Мб банок в нем, и это не беспокоило меня.
- Общей практикой является ограничение ваших внешних зависимостей от того, что предлагает догма J2EE: J2EE API (использование сервлетов, Ejbs, Jndi, JMX, JMS...). Ваше приложение должно быть "агностиком сервера".
- Включение зависимостей в ваше приложение (война, ухо, наблюдатель) самодокументируется: вы знаете, от каких библиотек зависит ваше приложение. С серверами libs вы должны четко документировать эти зависимости, поскольку они менее очевидны (и вскоре ваши разработчики забудут эту маленькую магию).
- Если вы обновите свой сервер приложений, вероятность того, что серверный lib, от которого вы зависите, также изменится. Редакторы AppServer не должны поддерживать совместимость в своих внутренних libs от версии к версии (и большую часть времени они этого не делают).
- Если вы используете широко распространенный lib, встроенный в ваш appServer (jakarta commons logging, aka jcl, приходит на ум), и вы хотите, чтобы его версия была доступна для получения последних функций, вы рискуете, что ваш appServer не будет поддерживать он.
- Если вы полагаетесь на статический объект сервера (в статическом поле класса сервера, например, на карте или в журнале), вам необходимо перезагрузить сервер приложений для очистки этого объекта. Вы теряете возможность горячего повторного развертывания своего приложения (старый серверный объект все еще существует между перераспределениями). Использование объектов allSphereServer (кроме тех, которые определены J2EE) может привести к тонким ошибкам, особенно если этот объект используется совместно несколькими приложениями. Поэтому я категорически отвергаю использование объектов, которые находятся в статическом поле приложения appServer lib.
Если вам абсолютно необходим "этот объект в этом банке appserver", попробуйте скопировать банку в ваше приложение, надеясь, что нет никакой зависимости от другой банки сервера и проверки политики загрузки приложений (я беру привычку ставить "родительский" последней "политики загрузки классов для всех моих приложений: я уверен, что я не буду" загрязнен "серверными банками, но я не знаю, является ли это" лучшей практикой ").
Ответ 5
Я поместил всю конфигурацию в базу данных. Контейнер (Tomcat, WebSphere и т.д.) Дает мне доступ к исходному соединению с базой данных, и с этого момента все выходит из базы данных. Это позволяет использовать несколько сред, кластеров и динамических изменений без простоев (или, по крайней мере, без повторного развертывания). Особенно приятным является возможность изменения уровня журнала на лету (хотя вам потребуется либо экран администратора, либо обновить фон, чтобы поднять изменения). Очевидно, что это работает только для вещей, которые не требуются для запуска приложения, но, как правило, вы можете быстро добраться до базы данных после запуска.