7

我一直在尝试使用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>

我收到以下错误:

线程“主”org.springframework.beans.factory.BeanCreationException 中的异常:在类路径资源 [applicationContext.xml] 中定义名称为“say”的 bean 创建错误:在设置 bean 属性“hello”时无法解析对 bean“hello”的引用; 嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'hello' is defined at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328) at org.springframework.beans.factory .support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:

我期待hello bean 将根据活动的 Maven 配置文件(在我的情况下为proddev)定义。我开始认为 Spring 活动配置文件(spring.profiles.active)可能与 Maven 配置文件完全无关。

有人可以解释我哪里出错了吗?(这甚至可以使用配置文件吗?)。

4

2 回答 2

12

我期待 hello bean 将根据活动的 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 packageweb.xml将具有正确的值spring.profile.active

于 2012-11-08T12:22:45.350 回答
2

感谢 maba(我会接受他的回答),我开始以不同的方式思考这个问题。

我已经修改了bean “say”,因为它需要延迟初始化,因为当它最初遇到时,嵌套的 bean 上下文还不存在。因此,新版本添加了一个新 bean 并更改了“say”定义,使其现在看起来像:

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

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

新的 InitProfile bean 是负责设置活动配置文件的 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 配置文件而异)。我也喜欢这种方法,因为我可以将它用于 Web 应用程序和命令行应用程序。

于 2012-11-08T14:01:36.883 回答