gpt4 book ai didi

java - Spring Boot 中的多态配置属性

转载 作者:太空宇宙 更新时间:2023-11-04 09:49:12 24 4
gpt4 key购买 nike

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

假设我们有以下 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 使用 Base 对象列表(而不是其子类)初始化带有 @ConfigurationProperties 注释的类。这实际上是一种预期的行为(出于安全考虑)。

是否有办法强制执行 SnakeYAML 的行为以使用子类,或实现任何类型的自定义反序列化提供程序?

最佳答案

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

Spring 没有将相同的属性绑定(bind)到多个 bean 的问题。您的实现不起作用的原因是您仅使用基类上的 @Component 注释向 ApplicationContext 注册了一个 bean。这告诉组件扫描器只有一个 Base 类型的单例。因为 FooBar 没有注册为 beans,所以它们不会被绑定(bind)。

如果您考虑使这些多态性的唯一原因是在基于 SnakeYAML 的配置中共享属性名称前缀,那么您实际上不需要引入多态关系,并且可以通过不同类中的公共(public)字段名称绑定(bind)到共享属性。

有很多方法可以实现您所要求的功能,但是以多态方式,以下是一些最直接简单的方法:

自声明多态ConfigurationProperties单例bean

不要将 @ConfigurationProperties@Component 注释应用于基类,而是将它们应用于具有相同属性名称前缀的具体类。这不是我的首选方法,因为每个 bean 都不会以其属性设置为条件,但它可能适合您的需求。根据您的 Spring 配置是否允许重新加载属性,Spring 将维护所有 bean 上的绑定(bind)。

注意:从 IntelliJ Idea 2018.3 开始,添加了检查配置文件以将重复的前缀键识别为错误。您可能想忽略这一点,或抑制警告。

我成功测试了以下内容:

基础.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;
}
}

酒吧.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;
}
}

应用程序.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 beans

如果缺少特定的属性,您可能不希望实例化某些具体实现。此外,您可能不希望将 @ConfigurationProperties@Component 注释耦合到每个具体类。此实现通过 Spring @Configuration bean 构造 ConfigurationProperties bean。配置 bean 确保它们仅通过属性存在检查有条件地构造。如果其他 Base bean 均不满足条件并且共享属性存在,则此实现还会创建一个具体类型 Base 的 bean。此处使用与上一个示例相同的单元测试并通过:

基础.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;
}
}

酒吧.java

package sample;

public class Bar extends Base {
private String barProperty;

public String getBarProperty() {
return barProperty;
}

public void setBarProperty(String barProperty) {
this.barProperty = barProperty;
}
}

示例配置.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();
}
}

应用程序.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());
}
}

关于java - Spring Boot 中的多态配置属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55013516/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com