Можно ли использовать один файл войны в нескольких средах? Нужно ли мне?

У меня есть веб-приложение Java на моей работе, и я хотел бы упростить, как мы развертываем наши среды DEV, QA и PROD.

Приложение запускает ряд свойств при запуске, а файлы свойств различаются для dev, qa и prod. Всякий раз, когда я хочу разворачиваться в определенную среду, я отбрасываю файл свойств, специфичный для среды, в папку своего приложения, строю войну и затем развертываю ее на одном из трех серверов tomcat 5.5.

То, что я хотел бы сделать, - это иметь один .war, который имеет свойства для всех сред, и попросить приложение опросить веб-сервер во время процесса init, чтобы выяснить, в какой среде находится приложение, и, следовательно, какие свойства загружать. Есть ли простой способ (или, если это не так, стандартный способ) сделать это?

Ответ 1

Это действительно зависит от того, для чего вы используете эти свойства.

Некоторые (например, источник данных, например) могут быть сконфигурированы в самом контейнере (Tomcat 5.5. Ресурсы JNDI, см. раздел источников JDBC как а).

Другим (специфичным для приложения) действительно может быть свойства. В этом случае ваши варианты:

  • Свойства пакета в файле WAR и загрузка соответствующего подмножества на основе какого-либо внешнего переключателя (либо переменной среды, либо свойства JVM).
  • Настройте процесс развертывания на каждом из серверов, на котором распакована война, и файл свойств (расположенный в предопределенном месте на этом сервере и специфичный для этого сервера) копируется на WEB-INF/classes (или другое подходящее место).

Насколько "это желаемая цель" идет - да, я так думаю. Наличие одной WAR для тестирования в QA/постановке, а затем развертывание на производство сокращает промежуточный шаг и, таким образом, оставляет меньше шансов на ошибки.

Обновить (на основе комментария):

Пункт № 1 выше относится к фактической переменной среды (например, что-то, что вы установили через SET ENV_NAME=QA в Windows или ENV_NAME=QA; export ENV_NAME в Linux). Вы можете прочитать его значение из своего кода с помощью System.getenv() и загрузить соответствующий файл свойств:

String targetEnvironment = System.getenv("TARGET_ENV");
String resourceFileName = "/WEB-INF/configuration-" + targetEnvironment + ".properties";
InputStream is = getServletContext().getResourceAsStream(resourceFileName);
Properties configuration = new Properties();
configuration.load(is);

Но да, вы можете вместо этого определить скалярное значение через JNDI (см. Записи среды в документе Tomcat):

<Context ...>
  <Environment name="TARGET_ENV" value="DEV" type="java.lang.String" override="false"/>
</Context>

и прочитайте его в своем приложении через

Context context = (Context) InitialContext().lookup("java:comp/env");
String targetEnvironment = (String) context.lookup("TARGET_ENV");
// the rest is the same as above

Дело в том, что если вы все равно будете использовать JNDI, вы также можете отказаться от своих файлов свойств и настроить все через JNDI. Ваши источники данных будут доступны вам, так как фактические ресурсы и основные свойства останутся скалярами (хотя они будут безопасными по типу).

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

Ответ 2

То, что вы делаете, - это несчастный случай, который должен произойти... Однажды война DEV закончится на сервере PROD, и по закону, превосходящему все законы природы, проблема будет обнаружена на 2AM. Не могу объяснить, почему это так, но когда-нибудь это произойдет. Поэтому одна война, на мой взгляд, определенно хорошая идея.

Вы можете установить системное свойство в соответствующем JVM (-Dcom.yourdomain.configpath =/where/you/store/configfiles) и извлечь это свойство с помощью

String value = System.getProperty("com.yourdomain.configpath", "defaultvalue_if_any"); 

Значение по умолчанию может указывать на то, что находится внутри войны (WEB-INF/...), или если нет значения по умолчанию, можно использовать, чтобы сделать некоторый шум регистрации во время загрузки предупреждением о неправильной конфигурации). Также обратите внимание, что этот метод не зависит от платформы, поэтому вы можете быть машиной Windows и сервером Linux, он может справиться с обоими. Обычно мы создаем subdir для каждого приложения в этом configpath, так как несколько приложений используют эту систему на сервере, и мы хотим держать вещи в порядке.

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

Ответ 3

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

Если вы хотите сохранить все свойства внутри войны (что упрощает развертывание, потому что тогда вам не нужно также развертывать файл свойств), вы можете сохранить один файл свойств в пути к классам, который идентифицирует сервер тип среды и использовать это для ключевых значений в файле свойств в вашем файле .war. Файл внешних свойств также может быть хорошим способом, возможно, для некоторых высокоуровневых конфигураций, которые мало меняются и используются во многих военных файлах.

Ответ 4

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

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

Ответ 5

Я предпочитаю один подход EAR или один WAR. Существует кое-что, что еще раз подтверждается и часто требуется с точки зрения безопасности о том, чтобы принять тот же самый EAR, который был только что протестирован, и перенести его прямо в следующее состояние (test > Production).

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

Существует множество примеров использования базы данных ResourceBundle.

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

Ответ 6

Задайте Systemproperty при запуске, который указывает на местоположение вашего файла свойств, а затем в вашем приложении вставьте это свойство и загрузите ваши настройки. Другое дело, что у меня есть два файла свойств, например, default.properties и external.properties. Они содержат одни и те же свойства, но default.properties содержит значение по умолчанию (работает большинство настроек времени), этот файл переходит в войну. Затем, если вы развернетесь в env. вы ищете внешние .properties, если найденный, который используется, если нет, то вы откатываете файл default.properties. Это дает хороший способ переопределить свойства, если это необходимо, но также имеет настройку по умолчанию. Это работает во многих моих развертываниях, но не может быть в вашем сценарии.

Ответ 7

Абсолютно одна WAR - лучший способ пойти. Задайте ресурсы, используя одни и те же имена JNDI в каждой среде, и если вам нужно определить, в какой среде вы работаете для бизнес-логики, используйте свойство System при запуске Tomcat.