Видимость bean-компонентов Spring 3.1 с использованием профилей определения bean-компонентов

Я экспериментировал с использованием Spring 3.1 профили определения bean и вложенные bean-компоненты. Я надеялся, что смогу определить разные bean-компоненты в зависимости от активного профиля. Рассмотрим следующий сильно упрощенный пример, в котором мой контекст Spring содержит что-то вроде

<bean id="say" class="test.Say" p:hello-ref="hello"/>

<beans profile="prod">
    <bean id="hello" class="test.Hello" p:subject="Production!"/>
</beans>

<beans profile="dev">
    <bean id="hello" class="test.Hello" p:subject="Development!"/>
</beans>

Я получаю следующую ошибку:

Исключение в потоке «main» org.springframework.beans.factory.BeanCreationException: ошибка при создании bean-компонента с именем say, определенным в ресурсе пути к классу [applicationContext.xml]: не удается разрешить ссылку на bean-компонент «hello» при установке свойства bean-компонента «hello» ; вложенное исключение - org.springframework.beans.factory.NoSuchBeanDefinitionException: в org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference (BeanDefinitionValueResolver.resolveReference (BeanDefinitionValueResolver.resolveReference (BeanDefinitionValue) или atrameRefinition8svalue.frameworkes.frameworkes.frameworkes.frameworkes.frameworkes / .support.BeanDefinitionValueResolver.resolveValueIfNeeded (BeanDefinitionValueResolver.java:106) в org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.apply (AbstractAutowireCapableBeanFactory.apply (AbstractAutowireCapableBeanFactory.apply)

Я ожидал, что компонент hello будет определен в соответствии с активным профилем Maven (в моем случае prod или dev). Я начинаю думать, что активные профили Spring (spring.profiles.active) могут быть совершенно не связаны с профилями Maven.

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


person Mark McLaren    schedule 08.11.2012    source источник


Ответы (2)


Я ожидал, что компонент hello будет определен в соответствии с активным профилем Maven (в моем случае prod или dev). Я начинаю думать, что активные профили Spring (spring.profiles.active) могут быть совершенно не связаны с профилями Maven.

Это правда, они не связаны.

Вот как это исправить:

Убедитесь, что web.xml, который у вас есть в папке src/main/webapp/WEB-INF/, имеет следующую настройку контекста:

<context-param>
    <param-name>spring.profile.active</param-name>
    <param-value>${profileName}</param-value>
</context-param>

Затем убедитесь, что в maven-war-plugin включена фильтрация для web.xml:

<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.3</version>
    <configuration>
        <filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
    </configuration>
</plugin>

И, наконец, в ваших профилях:

<profiles>
    <profile>
        <id>dev</id>
        <properties>
            <profileName>dev</profileName>
        </properties>
    </profile>
    <profile>
        <id>prod</id>
        <properties>
            <profileName>prod</profileName>
        </properties>
    </profile>
</profiles>

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

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <profileName>dev</profileName>
</properties>

Поэтому, если вы бежите без опции -P, будет использоваться профиль пружины dev.

При запуске mvn package web.xml будет иметь правильное значение для spring.profile.active.

person maba    schedule 08.11.2012
comment
Спасибо, маба, есть ли хороший способ использовать spring.profiles.active вне веб-приложения? например для модульных тестов - person Mark McLaren; 08.11.2012
comment
Если вы используете весенний тест, вы можете использовать аннотацию \ @ActiveProfiles вместе с другими стандартными аннотациями весеннего теста (\ @ContextConfiguration и т. Д.). Обычно я использую это для тестирования базы данных в разных средах. Я запускаю один против дерби во время тестовой цели maven, и у меня есть другой набор для oracle, который запускается для цели maven-теста интеграции. Я создаю абстрактные классы для определения тестов и \ @ContextConfiguration, расширяю их и использую @ActiveProfiles для превращения в модульный или интеграционный тест. - person Matt; 08.11.2012
comment
Спасибо, я застрял в этом деле, и вы меня спасли: D - person Vincent Vieira; 28.01.2014

Благодаря maba (чей ответ я приму) я начал думать об этом по-другому.

Я изменил компонент parent "say", потому что его нужно лениво инициализировать, потому что при его первоначальном обнаружении контексты вложенных компонентов не пока существуют. Таким образом, новая версия добавляет новый компонент и изменяет определение "say" таким образом, что теперь оно выглядит так:

<bean class="test.InitProfile" p:profiles="dev"/>

<bean id="say" class="test.Say" lazy-init="true" p:hello-ref="hello"/>

Новый компонент InitProfile - это компонент InitializingBean, отвечающий за настройку активных профилей.

Это содержит:

package test;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.StringUtils;

public class InitProfile implements InitializingBean, ApplicationContextAware {

    private ConfigurableApplicationContext ctx;
    private String[] profiles;

    public void setApplicationContext(ApplicationContext ac) throws BeansException {
        ctx = (ConfigurableApplicationContext) ac;
    }

    public void setProfiles(String inprofiles) {
        if (inprofiles.contains(",")) {
            profiles = StringUtils.split(inprofiles, ",");
        } else {
            profiles = new String[]{inprofiles};
        }
    }

    public void afterPropertiesSet() throws Exception {
        String[] activeProfiles = ctx.getEnvironment().getActiveProfiles();
        if (profiles != null && activeProfiles.length == 0) {
            ctx.getEnvironment().setActiveProfiles(profiles);
            ctx.refresh();
        }
    }
}

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

person Mark McLaren    schedule 08.11.2012