Загрузка различных свойств для разработки и развертывания
У меня очень распространенный случай использования - подключение к разным базам данных, когда моя программа находится в режиме разработки, в тестовом режиме или в режиме развертывания.
Теперь я делаю это, настраивая источник данных и передавая ему свойства ${...} через тег 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-компонентов, которые будут инициированы, он работает довольно хорошо в проектах, которые я выполняю в настоящее время, и мы все еще обнаруживаем больше свойств, которые нужно вставить в базу данных.
Пожалуйста, прочитайте:
<context:property-placeholder location="
classpath:application.properties,
classpath:application${spring.profiles.active}.properties"
ignore-unresolvable="true"/>
mvn clean install -Dspring.profiles.active="profile_name".