【问题标题】:Spring 3.1 bean visibility using bean definition profiles使用 bean 定义配置文件的 Spring 3.1 bean 可见性
【发布时间】:2012-10-28 15:05:32
【问题描述】:

我一直在尝试使用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 属性“你好”;嵌套异常是 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

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

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

【问题讨论】:

    标签: java spring maven applicationcontext


    【解决方案1】:

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

    没错,它们是无关的。

    以下是您可以解决的方法:

    确保您在src/main/webapp/WEB-INF/ 文件夹中的web.xml 具有以下上下文设置:

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

    然后确保maven-war-pluginweb.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 值。

    【讨论】:

    • 谢谢 maba,有没有在 web 应用程序之外使用 spring.profiles.active 的好方法?例如用于单元测试
    • 如果您使用的是 spring 测试,您可以使用 \@ActiveProfiles 注释以及其他标准的 spring 测试注释(\@ContextConfiguration 等)。我通常使用它来针对不同环境进行数据库测试。我在“测试” maven 目标期间与德比进行了一场比赛,并为 oracle 设置了另一组为“集成测试” maven 目标而战。我创建抽象类来定义测试和\@ContextConfiguration,并扩展它们,并使用@ActiveProfiles 将其转换为单元或集成测试。
    • 谢谢,我被这个案子困住了,你救了我:D
    【解决方案2】:

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

    我已经修改了 parent 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 应用程序和命令行应用程序。

    【讨论】:

      猜你喜欢
      • 2010-12-20
      • 2012-11-16
      • 1970-01-01
      • 2019-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-24
      • 1970-01-01
      相关资源
      最近更新 更多