Spring Boot中的多态配置属性

我想使用Spring@ConfigurationProperties注释在Spring上使用多态配置属性。

假设我们有以下POJO类。

public class Base {

private String sharedProperty;

public String getSharedProperty() {

return sharedProperty;

}

public String setSharedProperty(String sharedProperty) {

this.sharedProperty = sharedProperty;

}

}

public class Foo extends Base {

private String fooProperty;

public String getFooProperty() {

return fooProperty;

}

public String setFooProperty(String sharedProperty) {

this. fooProperty = fooProperty;

}

}

public class Bar extends Base {

private String barProperty;

public String getSharedProperty() {

return sharedProperty;

}

public String setBarProperty(String barProperty) {

this.barProperty = barProperty;

}

}

和配置属性类,

@Component

@ConfigurationProperties(prefix = "playground")

public class SomeConfigurationProperties {

private List<Base> mixed;

public List<Base> getMixed() {

return mixed;

}

public void setMixed(List<Base> mixed) {

this.mixed = mixed;

}

}

还有application.yml文件

playground:

mixed:

- shared-property: "shared prop"

foo-property: "foo prop"

- shared-property: "shared prop"

bar-property: "bar prop"

但是,使用这种配置,Spring @ConfigurationProperties使用Base对象列表而不是其子类来初始化-annotated

类。也就是说,实际上是一种预期的行为(由于安全问题)。

有没有一种方法可以强制 SnakeYAML 的行为以使用子类,或实现任何类型的自定义反序列化提供程序?

回答:

尽管可以实现自定义PropertySources和/或ConversionService,但不需要自定义反序列化提供程序。

Spring没有将相同属性绑定到多个bean的问题。您的实现无法正常工作的原因是,您只@Component在基类上带有注释的ApplicationContext中注册了一个bean

。这告诉组件扫描器只有一个单例类型Base。因为FooBar没有注册为bean,所以它们将不受约束。

如果要使这些多态性唯一的原因是在基于 SnakeYAML

的配置中共享属性名称前缀,那么您实际上不需要引入多态性关系,并且可以通过不同类中的公共字段名称绑定到共享属性。

有多种方法可以实现您所要的内容,但是可以采用多态的方式,以下是一些最简单的方法:

回答:

不要将@ConfigurationProperties@Component注释应用于基类,而是将它们应用于具有相同属性名称前缀的具体类。这不是我的首选方法,因为每个bean都不以其属性设置为条件,但是它可能适合您的需求。根据您的Spring

Configuration是否允许重新加载属性,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@Component注释耦合到每个具体的类。此实现通过Spring

@ConfigurationBean 构造ConfigurationProperties

Bean。配置bean确保仅通过属性存在检查有条件地构造它们。Base如果没有其他Basebean满足条件并且存在共享属性,则此实现还会创建一个具体类型的bean

。这里使用与上一个示例相同的单元测试,并通过:

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());

}

}

以上是 Spring Boot中的多态配置属性 的全部内容, 来源链接: utcz.com/qa/431947.html

回到顶部