Java 不可变@ConfigurationProperties
是否可以使用Spring Boot的Java 不可变@ConfigurationProperties,java,spring,spring-boot,properties-file,Java,Spring,Spring Boot,Properties File,是否可以使用Spring Boot的@ConfigurationProperties注释设置不可变(最终)字段?下面的例子 @ConfigurationProperties(prefix = "example") public final class MyProps { private final String neededProperty; public MyProps(String neededProperty) { this.neededProperty = neede
@ConfigurationProperties
注释设置不可变(最终)字段?下面的例子
@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是使用
newmyprops()创建的。
- 字段中的结果为
null
@ComponentScan
和@Component
提供MyProps
bean。
- 结果导致
->BeanInstantiationException
NoSuchMethodException:MyProps。
我让它工作的唯一方法是为每个非final字段提供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);
}
}
应用程序属性
类
@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;
}
}
}
显然,如果属性不仅仅是一个字符串,也就是一个可变对象,事情就更复杂了,但这是另一回事
更好的是,您可以创建一个配置容器
@ConfigurationProperties(prefix = "myapp")
public class ApplicationProperties {
private final List<MyConfiguration> configurations = new ArrayList<>();
public List<MyConfiguration> getConfigurations() {
return configurations
}
}
和application.yml as
myapp:
configurations:
- someProperty: one
- someProperty: two
- someProperty: other
您可以通过
@Value
注释设置字段值。这些可以直接放置在字段上,不需要任何设置程序:
@Component
public final class MyProps {
@Value("${example.neededProperty}")
private final String neededProperty;
public String getNeededProperty() { .. }
}
这种方法的缺点是:
- 您需要在每个字段上指定完全限定的属性名
- 验证不起作用(参见)
myapp.security.token-duration=30m
myapp.security.expired-tokens-check-interval=5m
myapp.scheduler.pool-size=2
代码:
从SpringBoot2.2开始,最终可以定义一个用
@ConfigurationProperties
修饰的不可变类 显示了一个示例。
您只需使用要绑定的字段(而不是setter方式)声明一个构造函数,并在类级别添加注释以指示应使用构造函数绑定。
因此,没有任何setter的实际代码现在就可以了:
@ConstructorBinding
@ConfigurationProperties(prefix = "example")
public final class MyProps {
private final String neededProperty;
public MyProps(String neededProperty) {
this.neededProperty = neededProperty;
}
public String getNeededProperty() { .. }
}
使用Lombok注释,代码如下所示:
@ConfigurationProperties(prefix = "example")
@AllArgsConstructor
@Getter
@ConstructorBinding
public final class MyProps {
private final String neededProperty;
}
此外,如果要直接自动关联此属性类,而不使用@Configuration
类和@EnableConfigurationProperties
,则需要将@ConfigurationPropertiesScan
添加到用@SpringBootApplication
注释的主应用程序类中
请参阅此处的相关文档:使用与 但是您可以使用
RequiredArgsConstructor
而不是AllArgsConstructor
考虑以下应用程序。属性
myprops.example.firstName=Peter
myprops.example.last name=Pan
myprops.example.age=28
注意:使用与属性一致的方法,我只是想说明这两种方法都是正确的(fistName
和last name
)
获取属性的Java类
@Service
public class SomeImplementation implements SomeInterface {
private final String someProperty;
@Autowired
public SomeImplementation(ApplicationProperties properties) {
this.someProperty = properties.getSomeProperty();
}
// ... other methods / properties
}
@Getter
@构造绑定
@所需参数构造函数
@ConfigurationProperties(前缀=“myprops.example”)
公共类舞台图
{
私有最终字符串名;
私有最终整数lastName;
私人最终整数年龄;
// ...
}
此外,还必须向构建工具添加依赖项 格雷德尔先生 或 pom.xml
org.springframework.boot
spring引导配置处理器
${spring.boot.version}
如果您为您的配置提供更精确的描述,请考虑在目录<代码> > SRC/main /Realth/Meta AF < < /P>中创建文件<代码>附加Spring配置元数据.JSON<代码>。
{
“财产”:[
{
“name”:“myprops.example.firstName”,
“类型”:“java.lang.String”,
“描述”:“此web服务的产品所有者的名字。”
},
{
“name”:“myprops.example.lastName”,
“类型”:“java.lang.String”,
“描述”:“此web服务的产品所有者的姓氏。”
},
{
“name”:“myprops.example.age”,
“类型”:“java.lang.Integer”,
“描述”:“自开发开始以来,此web服务的当前时代。”
}
}
(清理并编译以生效)
至少在IntelliJ中,当您将鼠标悬停在
应用程序.propoerties
中的属性上时,您可以获得自定义属性的清晰定价。这对其他开发人员非常有用
这为我的属性提供了一个简洁的结构,我正在为spring服务。据我所知,您试图做的事情不会在开箱即用的情况下完成。这很遗憾。当然,我可以用纯spring b来完成
@ConfigurationProperties(prefix = "example")
@AllArgsConstructor
@Getter
@ConstructorBinding
public final class MyProps {
private final String neededProperty;
}
annotationProcessor('org.springframework.boot:spring-boot-configuration-processor')