Подтвердить что ты не робот

Загрузить свойства среды для использования с PropertyPlaceholderConfigurer?

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

Я работаю над Java-приложением командной строки, используя Spring Batch и Spring. Я использую файл свойств вместе с PropertyPlaceholderConfigurer, но я немного уверен, что лучше всего обрабатывать файлы свойств для нескольких сред (dev, test и т.д.). Мой Googling запускает только программные способы загрузки свойств (то есть в самом Java-коде), который не работает для того, что я делаю.

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

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

<bean id="propertyConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:job.properties.${env}</value>
        </list>
    </property>
</bean>

Я наклоняюсь к последнему решению, но я также смотрю, есть ли лучший метод, который я пропускаю.

Я должен также упомянуть, что мне нужно сделать замену во время выполнения, а не в сборке. Для процесса, который мне требуется использовать, требуется отдельная сборка, которая будет продвигаться через среду для производства, поэтому я не могу использовать замену ala Maven или Ant.

4b9b3361

Ответ 1

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

Свойство Locations свойства PropertyPlaceHolderConfigurer может использовать различные типы ресурсов. Может также быть файловая система resouce или url? Таким образом, вы можете установить расположение файла конфигурации в файл на локальном сервере, а затем всякий раз, когда он будет запущен, он будет работать в режиме, указанном конфигурационным файлом на этом сервере. Если у вас есть определенные серверы для определенных режимов работы, это будет работать нормально.

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

Ответ 2

По сути, у вас есть готовый JAR, который вы хотите сбросить в другую среду, и без каких-либо изменений он забирает соответствующие свойства во время выполнения. Если это правильно, то действуют следующие подходы:

1) Положитесь на наличие файла свойств в домашнем каталоге пользователя.

Настройте PropertyPlaceholderConfigurer для ссылки на файл свойств, внешний для JAR, как это:

<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="ignoreUnresolvablePlaceholders" value="false"/>
    <property name="order" value="1"/>
    <property name="locations">
      <list>
        <!-- User home holds secured information -->
        <value>file:${user.home}/MyApp/application.properties</value>
      </list>
    </property>
  </bean>

Операционная система будет защищать содержимое файла application.properties, чтобы доступ к нему могли иметь только нужные люди. Поскольку этот файл не существует при первом запуске приложения, создайте простой script, который будет допрашивать пользователя для критических значений (например, имя пользователя, пароль, диалоги Hibernate и т.д.) При запуске. Предоставляйте обширную помощь и разумные значения по умолчанию для интерфейса командной строки.

2) Если ваше приложение находится в контролируемой среде, чтобы можно было увидеть базу данных, проблема может быть сведена к одному из создания основных учетных данных, используя технику 1) выше, чтобы подключиться к базе данных во время запуска контекста, а затем выполнить замену используя значения, считываемые через JDBC. Вам понадобится двухфазный подход к запуску приложения: фаза 1 вызывает родительский контекст с файлом application.properties, заполняющим JdbcTemplate и связанный с ним DataSource; фаза 2 вызывает основной контекст, который ссылается на родителя, так что JdbcTemplate может использоваться как сконфигурированный в JdbcPropertyPlaceholderConfigurer.

Примером такого кода может быть следующее:

public class JdbcPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

  private Logger log = Logger.getLogger(JdbcPropertyPlaceholderConfigurer.class);
  private JdbcTemplate jdbcTemplate;
  private String nameColumn;
  private String valueColumn;
  private String propertiesTable;

  /**
   * Provide a different prefix
   */
  public JdbcPropertyPlaceholderConfigurer() {
    super();
    setPlaceholderPrefix("#{");
  }

  @Override
  protected void loadProperties(final Properties props) throws IOException {
    if (null == props) {
      throw new IOException("No properties passed by Spring framework - cannot proceed");
    }
    String sql = String.format("select %s, %s from %s", nameColumn, valueColumn, propertiesTable);
    log.info("Reading configuration properties from database");
    try {
      jdbcTemplate.query(sql, new RowCallbackHandler() {

        public void processRow(ResultSet rs) throws SQLException {
          String name = rs.getString(nameColumn);
          String value = rs.getString(valueColumn);
          if (null == name || null == value) {
            throw new SQLException("Configuration database contains empty data. Name='" + name + "' Value='" + value + "'");
          }
          props.setProperty(name, value);
        }

      });
    } catch (Exception e) {
      log.fatal("There is an error in either 'application.properties' or the configuration database.");
      throw new IOException(e);
    }
    if (props.size() == 0) {
      log.fatal("The configuration database could not be reached or does not contain any properties in '" + propertiesTable + "'");
    }
  }

  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
    this.jdbcTemplate = jdbcTemplate;
  }

  public void setNameColumn(String nameColumn) {
    this.nameColumn = nameColumn;
  }

  public void setValueColumn(String valueColumn) {
    this.valueColumn = valueColumn;
  }

  public void setPropertiesTable(String propertiesTable) {
    this.propertiesTable = propertiesTable;
  }

}

Вышеуказанное затем будет настроено в Spring подобно этому (обратите внимание, что свойство order появляется после обычных $prefixed placeholders):

  <!-- Enable configuration through the JDBC configuration with fall-through to framework.properties -->
  <bean id="jdbcProperties" class="org.example.JdbcPropertyPlaceholderConfigurer">
    <property name="ignoreUnresolvablePlaceholders" value="false"/>
    <property name="order" value="2"/>
    <property name="nameColumn" value="name"/>
    <property name="valueColumn" value="value"/>
    <property name="propertiesTable" value="my_properties_table"/>
    <property name="jdbcTemplate" ref="configurationJdbcTemplate"/> <!-- Supplied in a parent context -->
  </bean>

Это позволит выполнить следующее в конфигурации Spring

<!-- Read from application.properties -->
<property name="username">${username}</property>  
...
<!-- Read in from JDBC as part of second pass after all $ have been fulfilled -->
<property name="central-thing">#{name.key.in.db}</property> 

3) Конечно, если вы находитесь в контейнере веб-приложений, вы просто используете JNDI. Но ты не такой, что не можешь.

Надеюсь, это поможет!

Ответ 3

Вы можете использовать <context:property-placeholder location="classpath:${target_env}configuration.properties" /> в Spring XML и настройте ${target_env} с помощью аргумента командной строки (-Dtarget_env=test.).

Начиная с Spring 3.1 вы можете использовать <context:property-placeholder location="classpath:${target_env:prod.}configuration.properties" /> и указать значение по умолчанию, тем самым устраняя необходимость установки значения в командной строке.

В случае, если Maven IS является опцией, переменная Spring может быть установлена ​​во время выполнения плагина, например. во время теста тестирования или интеграции.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.12</version>
    <configuration>
        <systemPropertyVariables>
            <target_env>test.</target_env>
        </systemPropertyVariables>
    </configuration>
</plugin>

Я предполагаю, что другие профили Maven также будут работать.

Ответ 4

Spring Конфигуратор хранителя свойств - несколько не столь очевидных опций

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:db.properties"></property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="${db.url.${mode}}" />
    <property name="username" value="${db.username.${mode}}" />
    <property name="password" value="${db.password.${mode}}" />
</bean>

${db.username.${mode}}: здесь "режим" определяет режим проекта (среда) - dev/prod Файл свойств выглядит так:

#Database properties
#mode dev/prod
mode=dev

#dev db properties
db.url.dev=jdbc:mysql://localhost:3306/dbname
db.username.dev=root
db.password.dev=root

#prod db properties
db.url.prod=jdbc:mysql://localhost:3306/dbname
db.username.prod=root
db.password.prod=root

Ответ 5

То, как я обычно делал это в прошлом, - это выполнить замену среды (dev/test/prod) каким-то образом на время пакета/развертывания.

Это может либо скопировать правильный файл конфигурации в нужное место на сервере, либо просто связать правильный файл конфигурации в пакете развертывания. Если вы используете Ant/Maven, это должно быть достаточно простым. Какой инструмент построения вы используете? Ant/Maven, который должен предоставить вам возможность заменить значение.

Другая альтернатива, использующая PropertyPlaceholderConfigurer, - это свойство SYSTEM_PROPERTIES_MODE_OVERRIDE. Вы можете использовать это, чтобы указать местоположение файла свойств, который вы хотите загрузить через системное свойство, см.

http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.html#SYSTEM_PROPERTIES_MODE_OVERRIDE

Надеюсь, что это поможет.

Ответ 6

В этом сообщении в блоге есть несколько хороших идей для переключения файлов свойств. Я закончил использование двойного PropertyPlaceholderConfigurer для использования системного свойства для указания файла конфигурации.

Ответ 7

Для замены времени сборки я использую свойства построения Maven для замены переменных. Вы можете определить, какие свойства загружать в файл настроек Maven settings.xml, и файл может быть специфичным для среды. Для производственных свойств с использованием PPC см. Это blog

Ответ 8

Я использую параметр classpath и настраиваю путь к классам в среде Jetty. В plug-maven-plugin вы можете установить каталог для тестовых классов и располагать там ваши тестовые источники.

В нелокальных средах (тест/производство) я использую флаг среды и отправляю соответствующие файлы в папку $JETTY_HOME/resources (которая встроена в путь класса Jetty)

Ответ 9

Привет после прочтения Spring в Action нашел решение, предоставленное Spring. Профиль или условный: вы можете создать несколько профилей, например. test, dev, prod и т.д.

Spring выделяет два отдельных свойства при определении того, какие профили активны: spring.profiles.active и Spring.profiles.default. Если Spring.profiles.active , то его значение определяет, какие профили активны. Но если spring .profiles.active не установлен, тогда Spring выглядит как Spring.profiles.default. Если ни spring.profiles.active и Spring.profiles.default установлен, тогда нет активных профилей, и создаются только те beans, которые arent, определенные как находящиеся в профиле.

Существует несколько способов установить эти свойства: 1 В качестве параметров инициализации DispatcherServlet 2 В качестве контекстных параметров веб-приложения 3 Как записи JNDI 4 В качестве переменных среды 5 Как свойства системы JVM 6 Использование аннотации @ActiveProfiles в классе тестирования интеграции