使用特定配置文件导入spring上下文

时间:2013-10-22 09:14:04

标签: spring classpath maven-3 spring-profiles

在我的java-spring-maven web应用程序中,我使用多个spring上下文(每个项目的单个上下文)。 为了简单起见,假设我有两个spring上下文:a.xml和b.xml,每个都属于一个项目:项目A和项目B,其中A依赖于B.

a.xml正在导入b.xml,如下所示:

<import resource="classpath*:/b.xml" />

因此,在加载a.xml时,也会加载b.xml。

现在,我的系统中有2个弹簧配置文件:我的上下文使用的测试生产(为每个配置文件加载不同的属性占位符)。

所以在a.xml中我得到了:

<!-- Production profile -->
<beans profile="production">
    <context:property-placeholder
        location="classpath:props-for-a.properties"
        ignore-unresolvable="true" ignore-resource-not-found="true" />
</beans>

<!-- Test profile -->
<beans profile="test">
    <context:property-placeholder
        location="classpath*:test-props-for-a.properties"
        ignore-unresolvable="true" />
</beans>

和b.xml中的相同约定(仅加载不同的属性文件)。 我的属性文件位于src / main / resources(生产文件)和src / test / resources(测试文件)下。

现在我有这样的单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/a.xml" })
@ActiveProfiles(profiles = "test")
public class SomeTestClass {

    @Test
    public void testMethod() {
    //Some Test
    }
}

在这种情况下,a.xml将加载到“test”配置文件中,并按预期加载所需的文件(test-props-for-a)。 b.xml是由a.xml导入的,但现在我遇到了一种奇怪的体验,我的属性值来自从b.xml加载的属性文件,不会被注入。

例如,如果我在我的属性文件中有此属性:

connection-ip=1.2.3.4

在我的课上我得到了:

@Value("${connection-ip}")
private String connectionIP;

connectionIP的值为“$ {connection-ip}”而不是“1.2.3.4”。

请注意,文件位置以classpath*开头,没有*我得到FileNotFoundException:

Caused by: org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: class path resource [test-props-for-b.properties] cannot be opened because it does not exist 

要清楚,文件test-props-for-b.properties位于项目B的src / test / resources下。为什么我会这样做?

如果我运行直接加载b.xml的测试(不是通过a.xml导入),它可以正常运行,文件test-props-for-b.properties中的测试属性按预期加载。

我做错了吗?这可能是个错误吗?如果是这样,你能建议一个解决方法吗?

更新

我从我的属性文件(test-props-for-b.properties)的路径中删除了星号(*)并调试了弹簧代码。在类ClassPathResource中,此方法抛出异常:

public InputStream getInputStream() throws IOException {
    InputStream is;
    if (this.clazz != null) {
        is = this.clazz.getResourceAsStream(this.path);
    }
    else {
        is = this.classLoader.getResourceAsStream(this.path);
    }
    if (is == null) {
        throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
    }
    return is;
}

以下是变量值:

this.clazz为null。 this.path保存文件名 test-props-for-b.properties

此命令返回null:

this.classLoader.getResourceAsStream(this.path);

为什么?我可以清楚地看到项目B的src / test / resources下的文件。

2 个答案:

答案 0 :(得分:1)

在调查问题后,这是我的结论:

如果我可以使用合适的类加载器,则可以轻松加载该文件,这意味着为了从项目A加载文件,项目A中任何类的类加载器都可以完成,同样对于项目B但是当使用spring的property-placeholder时,会使用ClassPathResource.java的类加载器,当它尝试从不同的项目加载资源时,它无法这样做(ClassPathResource会按属性占位符初始化,因此每个在我的情况下项目)。

我真的不知道如何修复它,目前我通过复制我的测试属性文件实现了一个丑陋的解决方法(将文件 test-props-for-b.properties 添加到src / test项目A的/ resources文件夹,这样我将它复制到项目B和A的src / test / resource中。

我仍在寻找一种更清洁的方式。

答案 1 :(得分:0)

您是否尝试过定义外部弹簧轮廓而不是@ActiveProfiles(profiles =“test”)?

一个例子是以这种方式在maven surefire插件中定义它:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>${surefire.version}</version>
            <configuration>
                <systemPropertyVariables>
                    <spring.profiles.active>test</spring.profiles.active>
                </systemPropertyVariables>
                <!-- THE REST OF CONFIGURATIONS -->
            </configuration>
        </plugin>