我有以下项目树:
├── app
│ ├── build.gradle
│ └── src
│ ├── main
│ │ ├── java
│ │ │ └── child
│ │ │ └── app
│ │ │ └── Application.java
│ │ └── resources
│ │ └── application-default.yaml
│ └── test
│ └── java
│ └── child
│ └── app
│ └── ApplicationTest.java
├── build.gradle
├── childA
│ ├── build.gradle
│ └── src
│ └── main
│ └── java
│ └── child
│ └── a
│ ├── BaseGreeterImpl.java
│ ├── ChildAConfig.java
│ ├── Greeter.java
│ └── MySpringProperties.java
├── childB
│ ├── build.gradle
│ └── src
│ └── main
│ └── resources
│ ├── application-test.yaml
│ └── childB.properties
├── childC
│ ├── build.gradle
│ └── src
│ ├── main
│ │ ├── java
│ │ │ └── child
│ │ │ └── c
│ │ │ ├── ChildCConfig.java
│ │ │ └── PropertyGreeterImpl.java
│ │ └── resources
│ │ └── childc.properties
│ └── test
│ └── java
│ └── child
│ └── c
│ ├── TestYamlImport.java
│ └── TestGreeter.java
└── settings.gradle
我有以下测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ChildCConfig.class }, loader = AnnotationConfigContextLoader.class)
@ActiveProfiles("test")
@SpringBootTest
public class TestYamlImport {
@Autowired
private MySpringProperties properties;
@Test
public void readChildAYaml() {
assertThat(properties.getName()).isEqualTo("it-is-another-thing");
}
}
我希望properties.getName()
能够从childB/src/main/resources/application-test.yaml中的资源childB
中读取值。
我得到null
GitHub:https://github.com/kopax/adk/tree/adk-spring
一个班轮:
git clone git@github.com:kopax/adk.git && cd adk && git checkout adk-spring && ./gradlew build --info
在复制项目中有一个名为childC/src/test/java/childC/TestGreeter.java的测试,通过childB.properties
导入证明它不是类路径问题。
所以这是我的问题:
使用@ConfigurationProperties
时弹簧是否以某种方式限制了类路径分辨率?
我还没有办法在application-test.yml
中从测试范围中初始化的配置@Bean
内阅读childA
childB
,这怎么可能?
答案 0 :(得分:2)
您使用AnnotationConfigContextLoader
代替(默认)SpringBootContextLoader
是否有任何特殊原因?您遇到的问题不是由类路径中缺少文件引起的(您可以将application-test.yaml
复制到任何具有相同结果的src/main/resources
或src/test/resources
,但事实是AnnotationConfigContextLoader
不会使用负责配置上下文的ConfigFileApplicationListener
来加载来自众所周知的文件位置的属性(例如您的application-{profile}.yaml
)。
您可以轻松比较使用每个加载器时加载的属性。首先,您可以检查AnnotationConfigContextLoader
的作用 - 只需在AbstractGenericContextLoader.java文件的第128行放置一个断点,并在您喜欢的IDE中运行调试器:
接下来,您可以调查变量context
- > environment
- > propertySources
- > propertySourceList
。您将找到5个房产来源:
他们都没有从application.yml
或application.properties
等配置文件中加载属性。
现在让我们做同样的事情但SpringBootContextLoader
课程。首先删除
loader = AnnotationConfigContextLoader.class
<{1>}中的并在SpringApplication.java文件中的第303行放置一个断点:
我们在应用程序上下文刷新之前是正确的。现在让我们调查变量MyEntityTest
- &gt; context
- &gt; environment
- &gt; propertySources
:
我们可以看到的第一个区别是,现在我们有7个属性源而不是前一个示例中的5个属性源。最重要的是 - propertySourceList
就在这里。此类使应用程序上下文能够识别ConfigFileApplicationListener.ConfigurationPropertySources
属性文件。
因此,您可以看到它只是使用正确的上下文加载器的问题。取代
application-{profile}.yaml
带
@ContextConfiguration(classes = { ChildCConfig.class }, loader = AnnotationConfigContextLoader.class)
或
@ContextConfiguration(classes = { ChildCConfig.class }, loader = SpringBootContextLoader.class)
因为使用@ContextConfiguration(classes = { ChildCConfig.class })
注释时此加载器是默认加载器,您将使测试像魅力一样传递。我希望它有所帮助。