Как использовать @ConfigurationProperties с записями?
В Java 16 появились записи , которые помогают сократить шаблонный код при написании классов, которые несут неизменяемые данные. Когда я пытаюсь использовать объект Record как bean, как показано ниже, я получаю следующее сообщение об ошибке:
@ConfigurationProperties("demo")
public record MyConfigurationProperties(
String myProperty
) {
}
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.demo.MyConfigurationProperties required a bean of type 'java.lang.String' that could not be found.
Как я могу использовать записи как
@ConfigurationProperties
?
7 ответов
Отвечая на свой вопрос.
Вышеупомянутая ошибка возникает из-за того, что Spring Boot не может создать bean-компонент из-за отсутствия конструктора без аргументов. Записи неявно объявляют конструктор с параметром для каждого члена.
Spring Boot позволяет нам использовать
@ConstructorBinding
аннотация для включения привязки свойств конструктором вместо методов установки (как указано в документации и ответе на этот вопрос ). Это также работает для записей, поэтому это работает:
@ConfigurationProperties("demo")
@ConstructorBinding
public record MyConfigurationProperties(
String myProperty
) {
}
У меня была такая же проблема с весенней загрузкой 3.0.0 и@ConstructorBinding
не рекомендуется.
Мне нужно было добавить:
@SpringBootApplication
@ConfigurationPropertiesScan
public class Application
Если вам нужно программно объявить значения по умолчанию:
@ConfigurationProperties("demo")
public record MyConfigurationProperties(String myProperty) {
@ConstructorBinding
public MyConfigurationProperties(String myProperty) {
this.myProperty = Optional.ofNullable(myProperty).orElse("default");
}
}
характеристики:
@ConfigurationProperties("demo")
public record MyConfigurationProperties(Optional<String> myProperty) {
@ConstructorBinding
public MyConfigurationProperties(String myProperty) {
this(Optional.ofNullable(myProperty));
}
}
@Validated
и
java.util.Optional
в сочетании:
@Validated
@ConfigurationProperties("demo")
public record MyConfigurationProperties(@NotBlank String myRequiredProperty,
Optional<String> myProperty) {
@ConstructorBinding
public MyConfigurationProperties(String myRequiredProperty,
String myProperty) {
this(myRequiredProperty, Optional.ofNullable(myProperty));
}
}
На основе этой проблемы с загрузкой Spring .
ConstructorBinding
и компактная форма конструктора в Spring Boot 3.1.0
Начиная с версии «spring-boot» «3.1.0»:
- Аннотация
org.springframework.boot.context.properties.ConstructorBinding
устарел и не может применяться к объявлению типа (класс, интерфейс, перечисление или запись), но может применяться к объявлению конструктора - Аннотация
org.springframework.boot.context.properties.bind.ConstructorBinding;
не может применяться к объявлению типа (класс, интерфейс, перечисление или запись), но может применяться к объявлению конструктора
Таким образом, мы можем объявитьrecord
и применитьorg.springframework.boot.context.properties.bind.ConstructorBinding
к компактной форме конструктора , которая по-прежнему выглядит лаконично:
@ConfigurationProperties
public record ApplicationProperties(/* Your properties here. E.g.:
String prop1,
Integer prop2,
NestedConfig nestedProps
*/) {
@ConstructorBinding
public ApplicationProperties {
}
}
Примечание . Не забудьте включить поддержку@ConfigurationProperties
аннотированные bean-компоненты в вашем приложении. Например:
@EnableConfigurationProperties(ApplicationProperties.class)
@SpringBootApplication
public class YourApplication {
public static void main(String[] args) {
SpringApplication.run(YourApplication.class, args);
}
}
С весенней загрузкой 3.0.4 я смог использовать записи напрямую без каких-либо аннотаций @ConstructorBinding.
@ConfigurationProperties(prefix = "app")
@Validated
public record ApplicationProperties(String version, FtpProperties ftp) {
public record FtpProperties(
@NotEmpty String host,
@Positive int port,
@NotEmpty String username) {}
}
При сопоставлении конфигурации YAML с использованием классового подхода не возникнет проблем, если вы используете аннотацию @Configuration.
Однако при переключении на использование записи для сопоставления Spring сообщит вам, что это окончательный тип и его нельзя проксировать и управлять им в контейнере.
Я обнаружил, что вы можете явно объявить в основном классе Spring, используя @EnableConfigurationProperties(XXProperties.class) или @ConfigurationPropertiesScan, что вам нужно добавить класс с аннотацией @ConfigurationProperties в контейнер, независимо от того, является ли это классом или записью. .
В версии 2.x Spring Boot, если вы хотите использовать тип записи для сопоставления файлов YAML, вам необходимо добавить к классу аннотацию @ConstructorBinding. Однако в версии Spring Boot 3.0 в этом больше нет необходимости, и он был помечен как устаревший.
@SpringBootApplication
//@EnableConfigurationProperties(YmlConfigDbProperties.class)
@ConfigurationPropertiesScan
public class AppMain {
public static void main(String[] args) {
SpringApplication.run(AppMain.class, args);
}
}
@ConfigurationProperties(prefix = "config.db")
//@Configuration
public record YmlConfigDbProperties(){}
В Spring-Boot 2.7.5 вам нужно будет только
- Аннотируйте запись с помощью
@ConfigurationProperties
- Аннотируйте основной класс с помощью
@ConfigurationPropertiesScan({RecordConfig.class})
. Эта часть важна, поскольку она сообщает Spring особенности класса Config и помогает ему зарегистрироваться как bean-компонент.enter code here
.