不可变的@ConfigurationProperties
不可变的@ConfigurationProperties
是否可能在Spring Boot的@ConfigurationProperties注解中使用不可变(final)字段?以下是示例:
@ConfigurationProperties(prefix = "example")
public final class MyProps {
private final String neededProperty;
public MyProps(String neededProperty) {
this.neededProperty = neededProperty;
}
public String getNeededProperty() { .. }
}
我迄今为止尝试过的方法有:
- 创建一个具有两个构造函数的MyProps类的@Bean
- 提供两个构造函数:一个是空的,一个带有neededProperty参数
- 该bean是通过new MyProps()创建的
- 导致字段为null
- 使用@ComponentScan和@Component提供MyProps bean。
- 导致BeanInstantiationException -> NoSuchMethodException: MyProps.
()
- 导致BeanInstantiationException -> NoSuchMethodException: MyProps.
我唯一能使其工作的方法是为每个非final字段提供getter/setter。
Immutable @ConfigurationProperties是一个问题,它的出现原因是希望在Spring Boot应用程序中使用不可变的配置属性。
解决方法如下:
1. 首先,在Java类中定义一个@ConfigurationProperties注解,并设置prefix属性为配置文件中属性的前缀。这个类必须是不可变的,即所有属性都必须是final的,并且必须有一个带有所有属性的构造函数。例如,在这个例子中,我们定义了一个名为StageConfig的类,它有三个属性:firstName、lastName和age。
2. 其次,需要将spring-boot-configuration-processor依赖添加到构建工具中,以支持@ConfigurationProperties注解的处理。在build.gradle或pom.xml文件中添加相应的依赖项。
3. 如果想为配置属性提供更详细的描述,可以创建一个additional-spring-configuration-metadata.json文件,并在其中定义每个属性的名称、类型和描述。该文件应该放在src/main/resources/META-INF目录下。在IntelliJ等IDE中,当鼠标悬停在配置文件中的属性上时,会显示该属性的描述信息。
4. 最后,编译并运行应用程序以使配置属性生效。
通过使用Immutable @ConfigurationProperties,我们可以在Spring Boot应用程序中使用不可变的配置属性,并提供详细的描述信息,方便其他开发人员使用和理解。
Immutable @ConfigurationProperties是一个经常出现的问题,我使用了一种略有不同的方法来解决这个问题,这使得我可以在类中使用final变量。
首先,我将所有的配置都放在一个地方(类)中,比如叫做ApplicationProperties。这个类有@ConfigurationProperties注解,并且有一个特定的前缀。它还在@Configuration注解中与配置类(或主类)一起列出。
然后,我将我的ApplicationProperties作为构造函数的参数,并在构造函数中将其赋值给一个final字段。
示例:
主类:
@SpringBootApplication public class Application { public static void main(String... args) throws Exception { SpringApplication.run(Application.class, args); } }
ApplicationProperties类:
@ConfigurationProperties(prefix = "myapp") public class ApplicationProperties { private String someProperty; // ... other properties and getters public String getSomeProperty() { return someProperty; } }
以及一个具有final属性的类:
public class SomeImplementation implements SomeInterface { private final String someProperty; public SomeImplementation(ApplicationProperties properties) { this.someProperty = properties.getSomeProperty(); } // ... other methods / properties }
我喜欢这种方法有很多不同的原因,比如如果我需要在构造函数中设置更多的属性,我的构造函数参数列表就不会很长,因为我始终只有一个参数(在我这里是ApplicationProperties);如果需要添加更多的final属性,我的构造函数保持不变(只有一个参数)- 这可能减少了其他地方的修改次数等。
希望这对你有帮助。
这是很多样板代码,相比之下只使用@ConfigurationProperties要好得多。
这是Java。更多的样板代码意味着更好的代码。
我真的不知道你是不是在开玩笑,但是我是认真的,虽然不完全正确,但也不差。
是的!这是一个半开玩笑(但是笑话中常常有真实的东西)。
以上是关于Immutable @ConfigurationProperties问题的原因和解决方法的整理。
从Spring Boot 2.2开始,可以定义一个使用@ConfigurationProperties
装饰的不可变类。文档中展示了一个例子。您只需声明一个带有要绑定字段的构造函数(而不是使用setter方法),并在类级别上添加@ConstructorBinding
注解,表示应使用构造函数绑定。因此,您的实际代码不再需要任何setter,如下所示:
@ConfigurationProperties(prefix = "example") public final class MyProps { private final String neededProperty; public MyProps(String neededProperty) { this.neededProperty = neededProperty; } public String getNeededProperty() { .. } }
注意,现在必须使用@ConstructorBinding
注解才能使其工作。在此之前(RC1版本),您必须使用@ConfigurationProperties
注解。有关为什么选择此注解的更多信息,请参考issue 18563
。
感谢您的评论。我根据当前的方式进行了更新。
在Spring Boot 3.x中,不再需要使用@ConstructorBinding
注解来标识单个构造函数。详情请参考https://github.com/spring-projects/spring-boot/wiki/...。