Загрузка различных свойств для разработки и развертывания

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

Теперь я делаю это, настраивая источник данных и передавая ему свойства ${...} через тег bean:property.

Однако, чтобы получить ${...}, я делаю

<context:property-placeholder properties-ref="myProperties" />

и в нижней части конфига XML, у меня есть

<beans profile=test>
   <util:properties id=myProperties>
   </util>
</beans>
<beans profile=dev,default>
   <util:properties id=myProperties>
</beans>
<beans profile=prod>
  <util:properties id="myProperties>
</beans>

Это кажется неэффективным, слишком многословным и подверженным ошибкам. Все учебные пособия по свойствам Spring говорят мне об этом контексте: свойство-заполнитель осведомлено об окружающей среде, а среда отвечает за профили, как мне это упростить? Мне интуитивно понятно, что есть более простой способ, я просто не могу понять это.

На самом деле, я ищу, чтобы указать профиль в контексте: свойства-заполнитель, или что-то в этом роде.

3 ответа

Решение

Я решил эту проблему однажды (задолго до того, как Spring поддержит профили): замена свойства Spring для тестирования и производства

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

Самый простой из них:

<context:property-placeholder
         location="classpath*:META-INF/spring/config-${spring.profiles.active}.properties" />

другой это:

<beans profile="normal">
    <context:property-placeholder 
             location="classpath*:META-INF/spring/config-normal.properties"/>
</beans>
<beans profile="test">    
      <context:property-placeholder
             location="classpath*:META-INF/spring/config-test.properties"/>
</beans>

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

Для первого подхода я нашел это решение, но я не проверял его:

<bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      <property name="locations">
        <list>
            <value>classpath*:META-INF/spring/*_${spring.profiles.active}.properties</value>
        </list>
      </property>
</bean>

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

В моих проектах я всегда экстернализировал свойства и превращал как можно больше свойств в параметры времени выполнения.

Просто представьте, что вам нужно снова связать Jenkins/Sonar/etc, так как ваша платформа не будет частью профиля со свойствами, находящимися в classpath. Я не думаю, что тогда это будут успешные проекты;)

Что касается Spring, вы можете использовать протокол file:// в свойстве configfigurer, позволяющий заменить свойство "dedault", исходящее из пути к классам. Таким образом, у вас есть два тега configurer с параметром заказа и другими свойствами. Вот пример:

    <jee:jndi-lookup id="configDirectory" jndi-name="configDirectory"
    resource-ref="true" default-value="." />
<jee:jndi-lookup id="datasource" jndi-name="jdbc/datasource"
    expected-type="javax.sql.DataSource" default-ref="localDatasource" />

<!-- Allows fetching properties from multiple locations: -->
<!-- external definition -> file://${configDirectory}/root-context.properties 
    -> declared in context.xml -->
<!-- standard web application bundle -> /WEB-INF/spring/root-context.properties -->
<!-- testing -> classpath:root-context.properties -->
<context:property-placeholder location="${configDirectory:.}/context.properties"
    order="9" ignore-resource-not-found="true" ignore-unresolvable="true" />
<context:property-placeholder
    location="/WEB-INF/spring/context.properties,
    classpath:context.properties"
    order="10" ignore-resource-not-found="true" ignore-unresolvable="true" />
<context:property-placeholder location="classpath:spring/default.properties"
    order="100" />

Таким образом, мы можем построить его локально, запустить наши модульные и интеграционные тесты во время сборки maven, запустить сборку на UAT и, если все в порядке, скопировать сборку из UAT в PROD без необходимости изменения файла war.

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

Все остальное хранится в базе данных как простые системные параметры (пары ключ-значение). Есть много свойств, которые не нужно фиксировать. Это включает в себя: LDAP, MailSender, определения папок, такие как tempdir и другие.

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

Пожалуйста, прочитайте:

https://examples.javacodegeeks.com/enterprise-java/spring/load-environment-configurations-and-properties-with-spring-example/

<context:property-placeholder  location="
       classpath:application.properties,
        classpath:application${spring.profiles.active}.properties"
                                      ignore-unresolvable="true"/>

mvn clean install -Dspring.profiles.active="profile_name".
Другие вопросы по тегам