英文:
Spring Boot property resolution fails tests at build time when adding a profile
问题 {#heading}
我有一个Spring Boot 2.7.14 应用程序,打包如下:
com.abc.globalpayments.feeds.downstream.dailycashreport
com.abc.globalpayments.feeds.downstream.dailycashreport.acquire
com.abc.globalpayments.feeds.downstream.dailycashreport.acquire.random
com.abc.globalpayments.feeds.downstream.dailycashreport.distribute
com.abc.globalpayments.feeds.downstream.dailycashreport.domain
com.abc.globalpayments.feeds.downstream.dailycashreport.generate
com.abc.globalpayments.feeds.downstream.dailycashreport.process
根目录下的 *.dailycashreport
包含入口点:
@Slf4j
@SpringBootApplication
@PropertySource(value = "classpath:feeds-config.yml", factory = com.abc.globalpayments.feeds.downstream.YamlPropertySourceFactory.class)
public class DcrDataFactoryApplication implements CommandLineRunner {
@Autowired
private SyntheticRunner runner; 数据源
public static void main(String[] args) {//}
上面的 YamlPropertySourceFactory 如下:
public class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(encodedResource.getResource());
Properties properties = factory.getObject();
return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
}
}
在 src/main/resources
下有以下 3 个资源:
application.yml:
spring:
application:
name: daily-cash-report-application
sftp:
host: dev
port: 22
user: dev
stagingDir: /opt/ccc/Data/Stage
tmpDir: /opt/ccc/abcd/tmp
#privateKey:
privateKey: file:///C:/Users/12345/AppData/Roaming/SSH/UserKeys/distributessh
chmod: 664
file:
stagingDir: /opt/ccc/Data/Stage
tmpDir: C:\tmp
feeds-config.yml
feeds:
downstream:
another-system:
output-file-name: other.txt
daily-cash-report:
output-file-name: dcr.txt
test:
records-to-generate:
pc: 10
dp: 5
z: 1
和 logback.xml
在测试中,我使用以下设置:
@SpringBootTest
class DataMarshallerServiceTest {
@Autowired
private DataMarshallerService cut;
@Autowired
//
上述设置构建并正常工作,但是一旦我尝试通过将 application.yml
重命名为 application-dev.yml
来引入一个 dev
配置文件,我开始在构建时遇到以下异常(测试执行的一部分):
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'sftp.host' in value "${sftp.host}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180)
这是我的STS IDE中的启动配置文件:
然而,错误在构建时出现,执行以下命令时:
mvn clean package -P dcr
这相当于STS中也存在的以下Maven配置:
我错过了什么,以使Spring配置文件开始正常工作?难道是因为 *App
配置了 YamlPropertySourceFactory
,其余的属性需要明确指定吗?
谢谢您的提前帮助。 英文:
I have a Spring Boot 2.7.14 application packaged as follows:
com.abc.globalpayments.feeds.downstream.dailycashreport
com.abc.globalpayments.feeds.downstream.dailycashreport.acquire
com.abc.globalpayments.feeds.downstream.dailycashreport.acquire.random
com.abc.globalpayments.feeds.downstream.dailycashreport.distribute
com.abc.globalpayments.feeds.downstream.dailycashreport.domain
com.abc.globalpayments.feeds.downstream.dailycashreport.generate
com.abc.globalpayments.feeds.downstream.dailycashreport.process
The root *.dailycashreport
package contains the entry point:
@Slf4j
@SpringBootApplication
@PropertySource(value = "classpath:feeds-config.yml", factory = com.abc.globalpayments.feeds.downstream.YamlPropertySourceFactory.class)
public class DcrDataFactoryApplication implements CommandLineRunner {
@Autowired
private SyntheticRunner runner; data sources
public static void main(String[] args) {//}
YamlPropertySourceFactory seen above is as follows:
public class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource&lt;?&gt; createPropertySource(String name, EncodedResource encodedResource) throws IOException {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(encodedResource.getResource());
Properties properties = factory.getObject();
return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
}
`}
`
There are the following 3 resources under src/main/resources
:
application.yml:
spring:
application:
name: daily-cash-report-application
sftp:
host: dev
port: 22
user: dev
stagingDir: /opt/ccc/Data/Stage
tmpDir: /opt/ccc/abcd/tmp
#privateKey:
privateKey: file:///C:/Users/12345/AppData/Roaming/SSH/UserKeys/distributessh
chmod: 664
`file:`
`
stagingDir: /opt/ccc/Data/Stage
tmpDir: C:\tmp
`
feeds-config.yml
feeds:
downstream:
another-system:
output-file-name: other.txt
daily-cash-report:
output-file-name: dcr.txt
test:
records-to-generate:
pc: 10
dp: 5
z: 1
and logback.xml
In tests, I'm using the following setup:
@SpringBootTest
class DataMarshallerServiceTest {
@Autowired
private DataMarshallerService cut;
@Autowired
`//
`
The above setup builds and works fine, however as soon as I'm trying to introduce a dev
profile by renaming application.yml
into application-dev.yml
, I start encountering the following exception as part of the build in tests execution:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'sftp.host' in value "${sftp.host}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180)
Here's the launch profile in my STS IDE:
However, the error manifests during the build time, when executing
mvn clear package -P dcr
which is equivalent to the following STS Maven config also present in STS:
What is it I'm missing so that Spring profiles start functioning properly?
Could it be that since the *App
has YamlPropertySourceFactory
configured, the rest of the properties need to be specified explicitly?
Thank you in advance.
答案1 {#1}
得分: 2
我做了以下假设并尝试验证它,看起来有效,所以我将其留在这里作为一个潜在的答案,可能会受到质疑。
显然测试需要指向正确的配置文件,这不是@SpringBootTest
注解本身的一部分。
以下三种配置似乎可以使构建工作:
选项1:
我在@SpringBootTest
之后更新了所有失败的测试用例,使用以下注解:
@ActiveProfiles(profiles = "dev")
并在application.yml
中添加了以下部分:
spring:
application:
name: daily-cash-report-application
profiles: dev
如果我将application.yml
重命名为application-dev.yml
,也可以工作。
选项2:
另一种更简单的方法如下:
-
无需像上面那样为所有测试添加额外的
@ActiveProfiles(profiles = "dev")
注解。 -
使用以下Maven命令运行构建:
mvn clean package -P dcr -Dspring.profiles.active=dev
并且
3. 使用*src/main/resources/*中的application-dev.yml
。
选项3:
既不需要:
- 添加
application-dev.yml
文件 - 也不需要指定额外的
@ActiveProfiles(profiles = "dev")
注解 - 也不需要在构建调用中指定特定配置文件
-Dspring.profiles.active=dev
- 或者将
-Dspring.profiles.active=dev
作为Maven的参数指定
只需:
将application.yml
的副本放入*src/test/resources/*文件夹中,以便通过mvn clean package -P dcr
进行测试执行。
我会让一位更有权威的人确认这些是否是正确的方法,并验证在Spring中的测试行为是否符合设计。
感谢阅读。 英文:
I've made the following assumption and an attempt to validate it, it seems to work, so I'll leave it here as a potential answer to be, potentially, challenged.
Apparently tests need to be pointed at the proper profile which is not part of the @SpringBootTest
annotation itself.
Either one of the following 3 configurations seem to make the build work:
Option 1:
I've updated all the failing test cases with the following annotation after the @SpringBootTest
:
@ActiveProfiles(profiles = "dev")
while adding the following stanza inside the application.yml
:
spring:
application:
name: daily-cash-report-application
profiles: dev
It also works without the above stanza if I rename application.yml
into application-dev.yml
.
Option 2:
Another, even simpler approach is as follows:
-
no need to annotate all tests with additional
@ActiveProfiles(profiles = "dev")
as above while -
running the build with the following Maven command instead:
mvn clean package -P dcr -Dspring.profiles.active=dev
and
- consuming the
application-dev.yml
out of src/main/resources/
Option 3
No need to either:
- adding an
application-dev.yml
file - or specifying an additional
@ActiveProfiles(profiles = "dev")
annotation - or needing to point to a specific profile as part of invocation of the build with
-Dspring.profiles.active=dev
, - or specifying
-Dspring.profiles.active=dev
as a parameter to Maven
Simply:
Drop a copy of application.yml
into src/test/resources/ folder so as to be picked up and used for tests execution via
mvn clean package -P dcr
I'll let someone more authoritative to confirm that these are the right approaches and to validate that this test behavior in Spring is by design.
Thank you for reading.
答案2 {#2}
得分: 0
你现在只提供了开发环境的属性文件,而没有标准的属性文件。请保留application.yml
,并额外添加一个application-dev.yml
文件。在标准属性文件中,您需要添加以下属性:
spring.profiles.active:
- dev
- another_profile
- and_one_more_profile
Spring现在将会搜索application-dev.yml
,并将其与application.yaml
一起使用。这样,您可以使用-dev配置文件中的属性来覆盖标准属性。
或者,正如Gweltaz Niquel在他的评论中指出的那样,您还可以通过系统参数来设置配置文件。 英文:
You are not providing the standard properties file but only the dev one. Keep the application.yml
and add a application-dev.yml
in addition. In the standard one you add the following property:
spring.profiles.active:
- dev
- another_profile
- and_one_more_profile
Spring will now search for application-dev.yml
in addition to the application.yaml
. This way you can override the standards with properties from the -dev profile.
Or, as Gweltaz Niquel pointed out in his comment, you can also set profiles via system parameter.