Хотя возможно реализовать пользовательские PropertySources и / или ConversionService , пользовательский поставщик десериализации не требуется.
В Spring нет проблем с привязкой одних и тех же свойств к нескольким bean-компонентам.Причина, по которой ваша реализация не работает, заключается в том, что вы регистрируете только один компонент с помощью ApplicationContext с аннотацией @Component
в базовом классе.Это говорит компонентному сканеру, что существует только один синглтон типа Base
.Поскольку Foo
и Bar
не зарегистрированы в качестве bean-компонентов, они не будут привязаны к.
Если единственная причина, по которой вы пытаетесь сделать эти полиморфные, - это использовать префиксы имен свойств в SnakeYAML на основе конфигурации, тогда вам фактически не нужно вводить полиморфные отношения, и вы можете привязать к общим свойствам общее имя поля в разных классах.
Есть много способов реализовать то, что вы запрашиваетеоднако, полиморфным образом, вот некоторые из самых простых простых:
Самообъявленные полиморфные синглтон-компоненты ConfigurationProperties
Вместо применения аннотаций @ConfigurationProperties
и @Component
кбазовый класс, примените их к конкретным классам, с тем же префиксом имени свойства.Это не будет моим предпочтительным подходом, поскольку каждый компонент не будет зависеть от того, какие свойства установлены, однако он может удовлетворить ваши потребности.В зависимости от того, позволяет ли ваша конфигурация Spring перезагружать свойства, Spring будет поддерживать привязки для всех bean-компонентов.
Примечание. Начиная с IntelliJ Idea 2018.3, был добавлен профиль проверки для определения дубликатов префиксных ключей.как ошибка.Вы можете игнорировать это или подавить предупреждения.
Я успешно проверил следующее:
Base.java
package sample;
public class Base {
private String sharedProperty;
public String getSharedProperty() {
return sharedProperty;
}
public void setSharedProperty(String sharedProperty) {
this.sharedProperty = sharedProperty;
}
}
Foo.java
package sample;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties("playground")
public class Foo extends Base {
private String fooProperty;
public String getFooProperty() {
return fooProperty;
}
public void setFooProperty(String fooProperty) {
this.fooProperty = fooProperty;
}
}
Bar.java
package sample;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties("playground")
public class Bar extends Base {
private String barProperty;
public String getBarProperty() {
return barProperty;
}
public void setBarProperty(String barProperty) {
this.barProperty = barProperty;
}
}
application.yml
playground:
shared-property: "shared prop"
foo-property: "foo prop"
bar-property: "bar prop"
SampleAppTest.java
package sample;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest
public class SampleAppTest {
@Autowired
public Environment environment;
@Test
public void test(@Autowired Bar bar, @Autowired Foo foo) {
assertEquals("shared prop", bar.getSharedProperty());
assertEquals("shared prop", foo.getSharedProperty());
assertEquals("bar prop", bar.getBarProperty());
assertEquals("foo prop", foo.getFooProperty());
}
@Test
public void testSuper(@Autowired List<Base> props) {
assertEquals(2, props.size());
}
}
Полиморфные компоненты ConfigurationProperties, зависящие от свойств
Возможно, вы не захотите создавать экземпляры определенных конкретных реализаций, если отсутствуют их конкретные свойства.Кроме того, вы можете не связывать аннотации @ConfigurationProperties
и @Component
с каждым конкретным классом.Эта реализация создает компоненты ConfigurationProperties с помощью компонента Spring @Configuration
.Компонент конфигурации гарантирует, что они построены только условно с помощью проверки существования свойства.Эта реализация также создает компонент конкретного типа Base
, если ни один из других компонентов Base
не удовлетворяет условиям и существуют общие свойства.Здесь используется тот же модульный тест из предыдущего примера, который проходит:
Base.java
package sample;
public class Base {
private String sharedProperty;
public String getSharedProperty() {
return sharedProperty;
}
public void setSharedProperty(String sharedProperty) {
this.sharedProperty = sharedProperty;
}
}
Foo.java
package sample;
public class Foo extends Base {
private String fooProperty;
public String getFooProperty() {
return fooProperty;
}
public void setFooProperty(String fooProperty) {
this.fooProperty = fooProperty;
}
}
Bar.java
package sample;
public class Bar extends Base {
private String barProperty;
public String getBarProperty() {
return barProperty;
}
public void setBarProperty(String barProperty) {
this.barProperty = barProperty;
}
}
SampleConfiguration.java
package sample;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SampleConfiguration {
@Bean
@ConfigurationProperties("playground")
@ConditionalOnProperty("playground.foo-property")
public Foo foo() {
return new Foo();
}
@Bean
@ConfigurationProperties("playground")
@ConditionalOnProperty("playground.bar-property")
public Bar bar() {
return new Bar();
}
@Bean
@ConfigurationProperties("playground")
@ConditionalOnProperty("playground.shared-property")
@ConditionalOnMissingBean(Base.class)
public Base base() {
return new Base();
}
}
application.yml
playground:
shared-property: "shared prop"
foo-property: "foo prop"
bar-property: "bar prop"
SampleAppTest.java
package sample;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest
public class SampleAppTest {
@Autowired
public Environment environment;
@Test
public void test(@Autowired Bar bar, @Autowired Foo foo) {
assertEquals("shared prop", bar.getSharedProperty());
assertEquals("shared prop", foo.getSharedProperty());
assertEquals("bar prop", bar.getBarProperty());
assertEquals("foo prop", foo.getFooProperty());
}
@Test
public void testSuper(@Autowired List<Base> props) {
assertEquals(2, props.size());
}
}