不可变的@ConfigurationProperties

是否可以使用Spring Boot的@ConfigurationProperties注释创建不可变(最终)字段? 以下示例

 @ConfigurationProperties(prefix = "example") public final class MyProps { private final String neededProperty; public MyProps(String neededProperty) { this.neededProperty = neededProperty; } public String getNeededProperty() { .. } } 

到目前为止我尝试过的方法:

  1. 使用两个构造函数创建MyProps类的MyProps
    • 提供两个构造函数:empty和neededProperty参数
    • 使用new MyProps()创建bean
    • 该字段的结果为null
  2. 使用@ComponentScan@Component提供MyProps bean。
    • BeanInstantiationException结果 – > NoSuchMethodException: MyProps.()

我得到它的唯一方法是为每个非最终字段提供getter / setter。

我必须经常解决这个问题,并且我使用了一种不同的方法,这允许我在类中使用final变量。

首先,我将所有配置保存在一个地方(类),比如称为ApplicationProperties 。 该类具有带有特定前缀的@ConfigurationProperties注释。 它还在针对配置类(或主类)的@EnableConfigurationProperties注释中列出。

然后我将我的ApplicationProperties作为构造函数参数提供,并对构造函数中的final字段执行赋值。

例:

主要课程:

 @SpringBootApplication @EnableConfigurationProperties(ApplicationProperties.class) 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; } } 

还有一个具有最终属性的类

 @Service public class SomeImplementation implements SomeInterface { private final String someProperty; @Autowired public SomeImplementation(ApplicationProperties properties) { this.someProperty = properties.getSomeProperty(); } // ... other methods / properties } 

我更喜欢这种方法有很多不同的原因,例如,如果我必须在构造函数中设置更多属性,我的构造函数参数列表不是“巨大”,因为我总是有一个参数(在我的例子中是ApplicationProperties ); 如果需要添加更多的final属性,我的构造函数保持不变(只有一个参数) – 这可能会减少其他地方的更改次数等。

我希望这会有所帮助

最后,如果你想要一个不可变对象,你也可以“破解”那个setter

 @ConfigurationProperties(prefix = "myapp") public class ApplicationProperties { private String someProperty; // ... other properties and getters public String getSomeProperty() { return someProperty; } public String setSomeProperty(String someProperty) { if (someProperty == null) { this.someProperty = someProperty; } } } 

显然,如果属性不仅仅是一个String,那是一个可变对象,事情就更复杂了,但这是另一个故事。

更好的是,您可以创建配置容器

 @ConfigurationProperties(prefix = "myapp") public class ApplicationProperties { private final List configurations = new ArrayList<>(); public List getConfigurations() { return configurations } } 

现在配置是没有的clas

 public class MyConfiguration { private String someProperty; // ... other properties and getters public String getSomeProperty() { return someProperty; } public String setSomeProperty(String someProperty) { if (someProperty == null) { this.someProperty = someProperty; } } } 

和application.yml as

 myapp: configurations: - someProperty: one - someProperty: two - someProperty: other