使用bean定义配置文件的Spring 3.1 bean可见性

时间:2012-11-08 12:00:26

标签: java spring maven applicationcontext

我一直在尝试使用Spring 3.1's bean definition profiles和嵌套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:错误   在类路径资源中定义名为'say'的bean   [applicationContext.xml]:无法解析bean'hello'的引用   设置bean属性'hello';嵌套异常是   org.springframework.beans.factory.NoSuchBeanDefinitionException:没有   名为'hello'的bean定义于   org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)     在   org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)     在   org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1360)     aJava结果:1

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

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

2 个答案:

答案 0 :(得分:12)

  

我希望根据活动的Maven配置文件(在我的例子中为prod或dev)定义hello bean。我开始认为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的正确值。

答案 1 :(得分:2)

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

我修改了 bean “说”,因为它需要懒惰地初始化,因为它最初遇到嵌套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应用程序和命令行应用程序。