Spring 当 application.properties 中没有相应的嵌套 key/value 对时,启动初始化嵌套配置绑定的新实例
Spring Boot initialize new instance for nested configuration binding when there are no corresponding nested key/value pairs in application.properties
我有如下配置 class。内部 class OptionalServiceConfigs
中的所有字段都有一个默认值,使用 @Value
注释,如下所示。
有时在我的 application.properties
文件中,它 没有 一个 service
前缀 属性。在这种情况下,我们希望加载一个 OptionalServiceConfigs
实例及其默认字段值。
@Configuration
@ConfigurationProperties(prefix = "myconf")
public class MyConfigs {
// ... rest of my configs
@Value("${service:?????}") // what to put here, or can I?
private OptionalServiceConfigs service; // this is null
// In this class all fields have a default value.
public static class OptionalServiceConfigs {
@Value("${mode:local}")
private String mode;
@Value("${timeout:30000}")
private long timeout;
// ... rest of getter and setters
}
// ... rest of getter and setters
}
但不幸的是,service
字段在使用其 getter 方法访问时是 null
。因为 spring boot 不会 在我的 application.properties
文件中找不到带有前缀 myconf.service.*
的 属性 键时初始化它的实例.
问题:
当属性文件中没有相应的前缀键时,如何使 service
字段连同其指定的默认字段值初始化为新实例?
我无法想象在 service
字段的注释 @Value("${service:?????}")
中放置一个值。
没有任何效果,试过,@Value("${service:}")
或 @Value("${service:new")
你可以试试这样的结构,对我来说很管用:
@Data
@Validated
@ConfigurationProperties(prefix = "gateway.auth")
@Configuration
public class AuthProperties {
@NotNull
private URL apiUrl;
@Valid
@NotNull
private Authentication authentication;
@Data
public static class Authentication {
@NotNull
private Duration accessTokenTtl;
@NotNull
private String accessTokenUri;
@NotNull
private String clientId;
@NotNull
private String clientSecret;
@NotNull
private String username;
@NotNull
private String password;
@Min(0)
@NonNull
private Integer retries = 0;
}
}
重要的是要有 getter 和 setter 才能使 Spring 对 ConfigurationProperties 进行后处理,为此我正在使用 Lombok (@Data)。
详情请看这里:
根据@M. Deinum的建议,对配置做了一些修改class。我是 Spring 的新手,我似乎误解了 Spring 在幕后的工作方式。
- 首先,我删除了内部 class(即
OptionalServiceConfigs
)中的所有 @Value
注释,以及 MyConfigs
[=50 中的 service
字段=].
- 然后,使用内联的默认值初始化所有内部 class 字段。
- 在
MyConfigs
的构造函数中,我为字段service
初始化了一个OptionalServiceConfigs
的新实例。
通过这样做,每当我的 application.properties
中有 no service
相关键时,已经使用默认值创建了一个新实例。
当有 is/are service
相关 key/s 时,那么 Spring 确实会将我的默认值覆盖为 application.properties
中的指定值仅 我指定的字段。
我认为从 Spring 的角度来看,当 none 时,它无法提前知道引用字段(即 service
字段)与配置相关它的密钥存在于配置文件中。这一定是 Spring 不初始化它的原因。很公平。
完整解决方案:
@Configuration
@ConfigurationProperties(prefix = "myconf")
public class MyConfigs {
// ... rest of my configs
private OptionalServiceConfigs service;
public static class OptionalServiceConfigs {
private String mode = "local";
private long timeout = 30000L;
// ... rest of getter and setters
}
public MyConfigs() {
service = new OptionalServiceConfigs();
}
// ... rest of getter and setters
}
我有如下配置 class。内部 class OptionalServiceConfigs
中的所有字段都有一个默认值,使用 @Value
注释,如下所示。
有时在我的 application.properties
文件中,它 没有 一个 service
前缀 属性。在这种情况下,我们希望加载一个 OptionalServiceConfigs
实例及其默认字段值。
@Configuration
@ConfigurationProperties(prefix = "myconf")
public class MyConfigs {
// ... rest of my configs
@Value("${service:?????}") // what to put here, or can I?
private OptionalServiceConfigs service; // this is null
// In this class all fields have a default value.
public static class OptionalServiceConfigs {
@Value("${mode:local}")
private String mode;
@Value("${timeout:30000}")
private long timeout;
// ... rest of getter and setters
}
// ... rest of getter and setters
}
但不幸的是,service
字段在使用其 getter 方法访问时是 null
。因为 spring boot 不会 在我的 application.properties
文件中找不到带有前缀 myconf.service.*
的 属性 键时初始化它的实例.
问题:
当属性文件中没有相应的前缀键时,如何使 service
字段连同其指定的默认字段值初始化为新实例?
我无法想象在 service
字段的注释 @Value("${service:?????}")
中放置一个值。
没有任何效果,试过,@Value("${service:}")
或 @Value("${service:new")
你可以试试这样的结构,对我来说很管用:
@Data
@Validated
@ConfigurationProperties(prefix = "gateway.auth")
@Configuration
public class AuthProperties {
@NotNull
private URL apiUrl;
@Valid
@NotNull
private Authentication authentication;
@Data
public static class Authentication {
@NotNull
private Duration accessTokenTtl;
@NotNull
private String accessTokenUri;
@NotNull
private String clientId;
@NotNull
private String clientSecret;
@NotNull
private String username;
@NotNull
private String password;
@Min(0)
@NonNull
private Integer retries = 0;
}
}
重要的是要有 getter 和 setter 才能使 Spring 对 ConfigurationProperties 进行后处理,为此我正在使用 Lombok (@Data)。
详情请看这里:
根据@M. Deinum的建议,对配置做了一些修改class。我是 Spring 的新手,我似乎误解了 Spring 在幕后的工作方式。
- 首先,我删除了内部 class(即
OptionalServiceConfigs
)中的所有@Value
注释,以及MyConfigs
[=50 中的service
字段=]. - 然后,使用内联的默认值初始化所有内部 class 字段。
- 在
MyConfigs
的构造函数中,我为字段service
初始化了一个OptionalServiceConfigs
的新实例。
通过这样做,每当我的 application.properties
中有 no service
相关键时,已经使用默认值创建了一个新实例。
当有 is/are service
相关 key/s 时,那么 Spring 确实会将我的默认值覆盖为 application.properties
中的指定值仅 我指定的字段。
我认为从 Spring 的角度来看,当 none 时,它无法提前知道引用字段(即 service
字段)与配置相关它的密钥存在于配置文件中。这一定是 Spring 不初始化它的原因。很公平。
完整解决方案:
@Configuration
@ConfigurationProperties(prefix = "myconf")
public class MyConfigs {
// ... rest of my configs
private OptionalServiceConfigs service;
public static class OptionalServiceConfigs {
private String mode = "local";
private long timeout = 30000L;
// ... rest of getter and setters
}
public MyConfigs() {
service = new OptionalServiceConfigs();
}
// ... rest of getter and setters
}