Статьи

Весна: Профили или Не Профили?


Я большой пользователь Spring, и должен признаться, что не следил за всеми последними добавлениями версии 3.1.
Одним из таких дополнений является понятие
профиля .

контекст

Профили предназначены для того случая, когда вы используете одну и ту же конфигурацию Spring для всех своих нужд, но когда есть небольшие различия. Наиболее частым случаем использования является источник данных. Например, во время моих интеграционных тестов я не использую сервер приложений, поэтому мой источник данных поступает из простого org.apache.commons.dbcp.BasicDataSource, настроенного с URL, именем класса драйвера, пользователем и паролем, например так:

<bean id="dataSource">
    <property name="driverClassName" value="${db.driver}" />
    <property name="url" value="${db.url}" />
    <property name="username" value="${db.username}" />
    <property name="password" value="${db.password}" />
</bean>

Обратите внимание, что существуют другие альтернативы BasicDataSource, такие как org.springframework.jdbc.datasource.SingleConnectionDataSource или com.mchange.v2.c3p0.ComboPooledDataSource.

В среде сервера приложений я использую другое определение компонента:

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/ds" />

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

Мое устаревшее решение

Чтобы иметь возможность переключаться с одного компонента на другой в зависимости от контекста, я использую следующее решение:

  • Я разделяю определение bean-компонента источника данных в его собственном конфигурационном файле Spring (соответственно spring-datasource-it.xml и spring-datasource.xml)
  • Для производственного кода я создаю основной конфигурационный файл Spring, который импортирует последний:

    <!--?xml version="1.0" encoding="UTF-8"?-->
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="...">
        <import resource="classpath:spring-datasource.xml"/>
        ...
    </beans>
  • Для тестирования интеграции я использую класс Spring Test в качестве родительского (например, AbstractTestNGSpringContextTests ) и настраиваю его с помощью аннотации ContextConfiguration . @ContextConfiguration имеет атрибут местоположения, который может быть установлен вместе с расположением всех необходимых фрагментов конфигурации Spring для запуска моего интеграционного теста.

Кроме того, как пользователь Maven, я могу аккуратно хранить файл spring-datasource.xml в src / main / resources и файл spring-datasource-it.xml в src / test / resources или в отдельных модулях. Учитывая это, конечный артефакт содержит только соответствующий компонент источника данных сервера приложений в моей конфигурации Spring: базовый пул данных безопасно остается в моем тестовом коде.

Профильное решение

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

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">
    ...
    <beans profile="integration">
        <bean id="dataSource">
            <property name="driverClassName" value="${db.driver}" />
            <property name="url" value="${db.url}" />
            <property name="username" value="${db.username}" />
            <property name="password" value="${db.password}" />
        </bean>
    </beans>
    <beans profile="production">
        <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/ds" />
    </beans>
</beans>

Теперь конфигурационный файл Spring содержит оба контекста.

Вывод

Я не совсем уверен, что такое использование профилей приносит что-то на стол (несмотря на то, что пример источника данных изображен повсюду в Интернете). Конечно, мы перешли от конфигурации времени сборки к конфигурации времени исполнения. Но единственное следствие, которое я вижу, состоит в том, что последние артефакты отправляются с информацией, не имеющей отношения к окружающей среде: в лучшем случае это плохая практика, а в худшем — недостаток безопасности.

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