Spring Boot属性解析在添加配置文件时在构建时失败测试。

huangapple go评论182阅读模式
英文:

Spring Boot property resolution fails tests at build time when adding a profile

问题

我有一个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中的启动配置文件:

Spring Boot属性解析在添加配置文件时在构建时失败测试。

然而,错误在构建时出现,执行以下命令时:

mvn clean package -P dcr

这相当于STS中也存在的以下Maven配置:

Spring Boot属性解析在添加配置文件时在构建时失败测试。

我错过了什么,以使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 = &quot;classpath:feeds-config.yml&quot;, 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 &#39;sftp.host&#39; in value &quot;${sftp.host}&quot;
	at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180)

Here's the launch profile in my STS IDE:

Spring Boot属性解析在添加配置文件时在构建时失败测试。

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:

Spring Boot属性解析在添加配置文件时在构建时失败测试。

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

得分: 2

我做了以下假设并尝试验证它,看起来有效,所以我将其留在这里作为一个潜在的答案,可能会受到质疑。

显然测试需要指向正确的配置文件,这不是@SpringBootTest注解本身的一部分。

以下三种配置似乎可以使构建工作:

选项1:

我在@SpringBootTest之后更新了所有失败的测试用例,使用以下注解:

@ActiveProfiles(profiles = "dev")

并在application.yml中添加了以下部分:

spring:
  application:
    name: daily-cash-report-application
  profiles: dev

如果我将application.yml重命名为application-dev.yml,也可以工作。

选项2:

另一种更简单的方法如下:

  1. 无需像上面那样为所有测试添加额外的@ActiveProfiles(profiles = "dev")注解。
  2. 使用以下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 = &quot;dev&quot;)

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:

  1. no need to annotate all tests with additional @ActiveProfiles(profiles = &quot;dev&quot;) as above while
  2. running the build with the following Maven command instead:
mvn clean package -P dcr -Dspring.profiles.active=dev

and

  1. 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 = &quot;dev&quot;) 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

得分: 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.

huangapple
  • 本文由 发表于 2023年8月10日 22:49:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76876873.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定