Propiedades de configuración con seguridad de tipo Spring

El uso de la anotación @Value("${property}") para inyectar propiedades de configuración a veces puede ser engorroso, especialmente si se trata de varias propiedades o si los datos son jerárquicos. Spring Boot proporciona una forma alternativa de manejar las propiedades, permitiendo que los beans fuertemente tipados administren y validen la configuración de su aplicación.

Consulte también la diferencia entre las propiedades de configuración @Value y typesafe.

1. Enlace de propiedad JavaBean

Como muestra el siguiente ejemplo, puede vincular un bean que declara las propiedades estándar de JavaBean.

Java

kotlin

@ConfigurationProperties("my.service")
public class MyProperties {

    private boolean enabled;

    private InetAddress remoteAddress;

    private final Security security = new Security();

    // getters / setters...

    public static class Security {

        private String username;

        private String password;

        private List<String> roles = new ArrayList<>(Collections.singleton("USER"));

        // getters / setters...

    }

}

El POJO anterior define las siguientes propiedades.

  • my.service.enabled, el valor predeterminado es `falso`.
  • my.service.remote-address, cuyo tipo puede ser proporcionado por `String`.
  • my.service.security.username, hay un objeto de seguridad anidado cuyo nombre está determinado por el nombre de esta propiedad. En particular, no hay absolutamente ningún uso de tipos allí, que pueden ser SecurityProperties.
  • mi.contraseña.de.seguridad.de.servicio.
  • my.service.security.role, hay una colección de String, el valor predeterminado es USER.

Asignadas a las propiedades de la clase @ConfigurationProperties disponible en Spring Boot, configuradas a través de archivos de propiedades, archivos YAML, variables de entorno y otros mecanismos. Estas propiedades son API públicas, pero los captadores/definidores de la clase en sí no significan que puedan usarse directamente (una oración En otras palabras, Spring también establece el valor a través de métodos públicos como getter/setter, así que no lo use).

Dicho diseño se basa en un constructor predeterminado sin argumentos, y los captadores y definidores suelen ser necesarios porque el enlace se implementa a través de descriptores de propiedades estándar de Java Beans (introspección de Java), al igual que en Spring MVC. El colocador se puede omitir en los siguientes casos.

  • Los mapas, cada vez que se inicializan, necesitan un getter, pero no necesariamente un setter, ya que el enlazador puede mutarlos.
  • Se puede acceder a las colecciones y matrices por índice (generalmente en YAML) o usando un solo valor separado por comas (propiedad). En este último caso, se requiere un colocador. Recomendamos siempre agregar un setter para tales tipos. Si inicializa una colección, asegúrese de que no sea inmutable (como en el ejemplo anterior).
  • Si se inicializan las propiedades anidadas de POJO (como el campo de seguridad en el ejemplo anterior), no se necesita un setter. Si desea que el enlazador cree instancias sobre la marcha utilizando su constructor predeterminado, necesita un setter.

Algunas personas usan Project Lombok para agregar getters y setters automáticamente. Asegúrese de que Lombok no genere ningún constructor específico para dicho tipo, ya que el contenedor lo usa automáticamente para crear instancias de objetos.

Finalmente, solo se consideran las propiedades estándar de Java Bean, no se admite el enlace a propiedades estáticas.

2. Enlace del constructor

El ejemplo de la sección anterior se puede reescribir de forma inmutable, como se muestra en el siguiente ejemplo.

Java

@ConfigurationProperties("my.service")
public class MyProperties {

    // fields...

    public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
        this.enabled = enabled;
        this.remoteAddress = remoteAddress;
        this.security = security;
    }

    // getters...

    public static class Security {

        // fields...

        public Security(String username, String password, @DefaultValue("USER") List<String> roles) {
            this.username = username;
            this.password = password;
            this.roles = roles;
        }

        // getters...

    }

}

En esta configuración, la presencia de un "constructor parametrizado" único significa que ese constructor debe usarse para el enlace. Esto significa que el enlazador encontrará un constructor con los parámetros que desea enlazar. Si su clase tiene varios constructores, puede usar la anotación @ConstructorBinding para especificar qué constructor usar para el enlace del constructor. Si desea elegir no vincular un constructor para una clase con solo un "constructor parametrizado", el constructor debe anotarse con @Autowired. El enlace de constructor se puede usar con Record. No es necesario usar @ConstructorBinding a menos que su registro tenga varios constructores.

Los miembros anidados de las clases vinculadas al constructor (como Seguridad en el ejemplo anterior) también se vincularán a través de sus constructores.

Los valores predeterminados se pueden especificar utilizando @DefaultValue en los parámetros del constructor y los componentes de registro. El servicio de conversión se aplicará para forzar el valor de cadena de la anotación al tipo de destino para el atributo que falta.

Haciendo referencia al ejemplo anterior, si no hay propiedades vinculadas a la seguridad, la instancia de MyProperties contendrá un valor nulo de tipo seguridad. Para que contenga una instancia de seguridad no nula, incluso si no tiene propiedades vinculadas (al usar Kotlin, esto requeriría que los parámetros de nombre de usuario y contraseña de seguridad se declararan anulables, ya que no tienen un valor predeterminado), use un @ DefaultValue vacío anotación.

Java

kotlin

public MyProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
    this.enabled = enabled;
    this.remoteAddress = remoteAddress;
    this.security = security;
}

Para usar el enlace del constructor, la clase debe estar habilitada usando @EnableConfigurationProperties o el escaneo de propiedades de configuración. No puede usar el enlace de constructor en beans creados a través de mecanismos Spring normales (como beans @Component, beans creados usando métodos @Bean o beans cargados usando @Import ).

Para usar el enlace del constructor en una imagen nativa, la clase debe compilarse con el argumento -parameters. Esto se configura automáticamente si usa el complemento Gradle de Spring Boot o si usa Maven con spring-boot-starter-parent.

No se recomienda usar java.util.Optional con @ConfigurationProperties, ya que se usa principalmente como tipo de devolución. Por lo tanto, no es adecuado para la inyección de propiedades de configuración. Para mantener la coherencia con otros tipos de propiedades, si declara una propiedad Opcional, pero no tiene ningún valor, se vinculará un valor nulo en lugar de un Opcional vacío.

3. Habilite la clase @ConfigurationProperties

Spring Boot proporciona la infraestructura para enlazar los tipos @ConfigurationProperties y registrarlos como beans. Puede habilitar las propiedades de configuración clase por clase o habilitar el análisis de propiedades de configuración, que funciona de manera similar al análisis de componentes.

A veces, las clases anotadas con @ConfigurationProperties pueden no ser adecuadas para escanear, por ejemplo, si está desarrollando sus propias configuraciones automáticas o desea habilitarlas de forma condicional. En estos casos, use la anotación @EnableConfigurationProperties para especificar la lista de tipos a manejar, que se pueden anotar en cualquier clase @Configuration, como se muestra en el siguiente ejemplo.

Java

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SomeProperties.class)
public class MyConfiguration {

}

Java

@ConfigurationProperties("some.properties")
public class SomeProperties {

}

Para usar el escaneo de propiedades de configuración, agregue la anotación @ConfigurationPropertiesScan a su aplicación. Por lo general, se agrega a la clase principal anotada con @SpringBootApplication, pero también se puede agregar a cualquier clase de @Configuration. De manera predeterminada, el escaneo comenzará desde el paquete donde se encuentra la anotación.Si desea personalizar el escaneo de otros paquetes, puede consultar lo siguiente.

Java

@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {

}

Cuando un bean @ConfigurationProperties se analiza mediante las propiedades de configuración o se registra a través de @EnableConfigurationProperties, el bean tiene un nombre general: <prefijo>-<fqn>, donde <prefijo> es el prefijo de clave de entorno especificado en la anotación @ConfigurationProperties y <fqn> es el bean El nombre completo del . Si la anotación no proporciona ningún prefijo, solo se utiliza el nombre completo del bean.

Asumiendo que está en el paquete com.example.app, el nombre del bean para el ejemplo anterior de SomeProperties es some.properties-com.example.app.SomeProperties.

Recomendamos que @ConfigurationProperties solo se ocupe del entorno, especialmente para no inyectar otros beans del contexto. Para casos de esquina (casos especiales), puede usar la inyección de setter o cualquier interfaz *Aware proporcionada por el marco (como EnvironmentAware, si necesita acceder a Environment). Si aún desea inyectar otros beans usando el constructor, el bean de propiedad de configuración debe anotarse con @Component y usar el enlace de propiedad basado en JavaBean.

Cuarto, use la clase @ConfigurationProperties

Esta configuración funciona particularmente bien con la configuración YAML externa de SpringApplication, como se muestra en el siguiente ejemplo.

my:
  service:
    remote-address: 192.168.1.1
    security:
      username: "admin"
      roles:
      - "USER"
      - "ADMIN"

Para usar los beans @ConfigurationProperties, los inyecta de la misma manera que otros beans, como se muestra en el siguiente ejemplo.

Java

@Service
public class MyService {

    private final MyProperties properties;

    public MyService(MyProperties properties) {
        this.properties = properties;
    }

    public void openConnection() {
        Server server = new Server(this.properties.getRemoteAddress());
        server.start();
        // ...
    }

    // ...

}

El uso de @ConfigurationProperties también le permite generar archivos de metadatos que los IDE pueden usar para la funcionalidad de "completado automático" de propiedades de configuración. Mira el apéndice para los detalles.

5. Configuración de terceros

Además de anotar una clase con @ConfigurationProperties, también puede usarla en métodos públicos de @Bean. Esto es especialmente útil cuando desea vincular propiedades a componentes de terceros fuera de su control.

Para configurar un bean desde las propiedades del entorno, agregue @ConfigurationProperties a su registro de bean, como se muestra en el siguiente ejemplo.

Java

@Configuration(proxyBeanMethods = false)
public class ThirdPartyConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "another")
    public AnotherComponent anotherComponent() {
        return new AnotherComponent();
    }

}

Todas las propiedades de JavaBean definidas con el prefijo another se asignarán al Bean AnotherComponent de manera similar al ejemplo anterior de SomeProperties.

6. Encuadernación suelta

Spring Boot usa algunas reglas flexibles cuando vincula las propiedades del entorno a los beans @ConfigurationProperties, por lo que no es necesario que haya una coincidencia exacta entre los nombres de las propiedades del entorno y los nombres de las propiedades del bean. Esto es útil, los ejemplos comunes incluyen nombres de propiedades separados por guiones (por ejemplo, context-path se une a contextPath ) y nombres de propiedades en mayúsculas (por ejemplo, PORT se une a port ).

Para demostrar un ejemplo, considere la siguiente clase @ConfigurationProperties.

Java

@ConfigurationProperties(prefix = "my.main-project.person")
public class MyPersonProperties {

    private String firstName;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

}

Para el código anterior, se pueden usar los siguientes nombres de propiedad.

Tabla 3. Unión relajada

Propiedad

Nota

mi.proyecto-principal.persona.primer-nombre

Estilo kebab (separados por guiones), recomendado para usar en archivos .properties y YAML.

mi.proyecto-principal.persona.nombre

Sintaxis estándar de camelCase.

mi.proyecto-principal.persona.nombre

Guión bajo, que es un formato alternativo para archivos .properties y YAML.

MI_PROYECTO PRINCIPAL_PERSONA_FIRSTNAME

Formato en mayúsculas, se recomienda utilizar el formato en mayúsculas cuando se utilizan variables de entorno del sistema.

El valor del prefijo de la anotación debe estar en estilo kebab (en minúsculas y separado por -, como my.main-project.person).

Tabla 4. Reglas de vinculación relajadas para cada fuente de propiedad

fuente de atributos

simple

la lista

Archivo de propiedades

joroba, kebab, guión bajo

Sintaxis de lista estándar usando [ ] o valores separados por comas

archivo YAML

joroba, kebab, guión bajo

Sintaxis de lista YAML estándar o valores separados por comas

Variable ambiental

Mayúsculas, con guiones bajos como separadores (consulte Vinculación desde variables de entorno).

Valores numéricos rodeados de guiones bajos (ver Vinculación desde variables de entorno)

Propiedades del sistema

joroba, kebab, guión bajo

Sintaxis de lista estándar usando [ ] o valores separados por comas

我们建议,在可能的情况下,属性应以小写的kebab格式存储,例如 my.person.first-name=Rod 。 

绑定Map

当绑定到 Map 属性时,你可能需要使用一个特殊的括号符号,以便保留原始的 key 值。 如果key没有被 [ ] 包裹,任何非字母数字、- 或 . 的字符将被删除。

例如,考虑将以下属性绑定到一个 Map<String,String>。

Properties

Yaml

my.map.[/key1]=value1
my.map.[/key2]=value2
my.map./key3=value3

对于YAML文件,括号需要用引号包裹,以使key被正确解析。

上面的属性将绑定到一个 Map ,/key1,/key2 和 key3 作为map的key。 斜线已经从 key3 中删除,因为它没有被方括号包裹。

当绑定到标量值时,带有 . 的键不需要用 [] 包裹。 标量值包括枚举和所有 java.lang 包中的类型,除了 Object 。 将 a.b=c 绑定到 Map<String, String> 将保留键中的 . ,并返回一个带有 {"a.b"="c"} Entry的Map。 对于任何其他类型,如果你的 key 包含 . ,你需要使用括号符号。 例如,将 a.b=c 绑定到 Map<String, Object> 将返回一个带有 {"a"={"b"="c"} entry的Map,而 [a.b]=c 将返回一个带有 {"a.b"="c"} entry 的Map。

从环境变量绑定

例如,Linux shell变量只能包含字母(a 到 z 或 A 到 Z )、数字( 0 到 9 )或下划线字符( _ )。 按照惯例,Unix shell变量的名称也将采用大写字母。

Spring Boot宽松的绑定规则被设计为尽可能地与这些命名限制兼容。

要将规范形式的属性名称转换为环境变量名称,你可以遵循这些规则。

  • 用下划线(_)替换点(.)。
  • 删除任何破折号(-)。
  • 转换为大写字母。

例如,配置属性 spring.main.log-startup-info 将是一个名为 SPRING_MAIN_LOGSTARTUPINFO 的环境变量。

环境变量也可以在绑定到对象列表(List)时使用。 要绑定到一个 List,在变量名称中,元素编号(索引)应该用下划线包裹。

例如,配置属性 my.service[0].other 将使用一个名为 MY_SERVICE_0_OTHER 的环境变量。

七、 合并复杂的类型

当List被配置在多个地方时,覆盖的作用是替换整个list。

例如,假设一个 MyPojo 对象的 name 和 description 属性默认为 null。 下面的例子从 MyProperties 中暴露了一个 MyPojo 对象的列表。

Java

@ConfigurationProperties("my")
public class MyProperties {

    private final List<MyPojo> list = new ArrayList<>();

    public List<MyPojo> getList() {
        return this.list;
    }

}

考虑以下配置。

Properties

Yaml

my.list[0].name=my name
my.list[0].description=my description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name

如果 dev 配置文件未被激活,MyProperties.list 包含一个 MyPojo 条目,如之前定义的那样。 然而,如果 dev 配置文件被激活,list 仍然只包含一个条目(name 为 my another name,description为 null)。 这种配置不会在列表中添加第二个 MyPojo 实例,也不会合并项目。

当一个 List 在多个配置文件中被指定时,将使用具有最高优先级的那个(并且只有那个)。 考虑下面的例子。

Properties

Yaml

my.list[0].name=my name
my.list[0].description=my description
my.list[1].name=another name
my.list[1].description=another description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name

在前面的例子中,如果 dev 配置文件是激活的,MyProperties.list 包含 一个 MyPojo 条目(name 是 my another name,description是 null)。 对于YAML,逗号分隔的列表和YAML列表都可以用来完全覆盖列表的内容。

对于 Map 属性,你可以用从多个来源获取的属性值进行绑定。 然而,对于多个来源中的同一属性,使用具有最高优先级的那个。 下面的例子从 MyProperties 暴露了一个 Map<String, MyPojo>。

Java

Kotlin

@ConfigurationProperties("my")
public class MyProperties {

    private final Map<String, MyPojo> map = new LinkedHashMap<>();

    public Map<String, MyPojo> getMap() {
        return this.map;
    }

}

考虑以下配置。

Properties

Yaml

my.map.key1.name=my name 1
my.map.key1.description=my description 1
#---
spring.config.activate.on-profile=dev
my.map.key1.name=dev name 1
my.map.key2.name=dev name 2
my.map.key2.description=dev description 2

如果 dev 配置文件没有激活,MyProperties.map 包含一个key为 key1 的条目(name为 my name 1 ,description为 my description 1 )。 然而,如果 dev 配置文件被激活,map 包含两个条目,key为 key1 (name为 dev name 1,description为 my description 1 )和 key2(name为 dev name 2,description为 dev description 2)。

前面的合并规则适用于所有属性源的属性,而不仅仅是文件。

八、属性(Properties)转换

当Spring Boot与 @ConfigurationProperties Bean绑定时,它试图将外部application properties强制改为正确的类型。 如果你需要自定义类型转换,你可以提供一个 ConversionService bean(Bean的名称为 conversionService )或自定义属性编辑器(通过 CustomEditorConfigurer bean)或自定义 Converters Bean(使用 @ConfigurationPropertiesBinding 注解)。

由于这个Bean是在应用程序生命周期的早期被请求的,请确保限制你的 ConversionService 所使用的依赖关系。 通常情况下,你所需要的任何依赖关系在创建时可能没有完全初始化。 如果你的自定义 ConversionService 不需要配置keys coercion,你可能想重命名它,并且只依赖用 @ConfigurationPropertiesBinding 限定的自定义转换器。

转换为 Duration

Spring Boot对表达持续时间有专门的支持。 如果你公开了一个 java.time.Duration 属性,application properties中的以下格式就可用。

  • 普通的 long (使用毫秒作为默认单位,除非指定了 @DurationUnit )。
  • 标准的ISO-8601格式 由 java.time.Duration 使用。
  • 一个更易读的格式,其中值和单位是耦合的(10s 表示10秒)。

请考虑以下例子。

Java

@ConfigurationProperties("my")
public class MyProperties {

    @DurationUnit(ChronoUnit.SECONDS)
    private Duration sessionTimeout = Duration.ofSeconds(30);

    private Duration readTimeout = Duration.ofMillis(1000);

    // getters / setters...

}

要指定一个30秒的会话超时, 30 、 PT30S 和 30s 都是等价的。 读取超时为500ms,可以用以下任何一种形式指定。 500, PT0.5S 和 500ms.

你也可以使用如下支持的时间单位。

  • ns 纳秒
  • us 微秒
  • ms 毫秒
  • s 秒
  • m 分
  • h 小时
  • d 天

默认单位是毫秒,可以使用 @DurationUnit 来重写,如上面的例子所示。

如果你喜欢使用构造函数绑定,同样的属性可以被暴露出来,如下面的例子所示。

Java

@ConfigurationProperties("my")
public class MyProperties {

    // fields...

    public MyProperties(@DurationUnit(ChronoUnit.SECONDS) @DefaultValue("30s") Duration sessionTimeout,
            @DefaultValue("1000ms") Duration readTimeout) {
        this.sessionTimeout = sessionTimeout;
        this.readTimeout = readTimeout;
    }

    // getters...

}

 如果你要升级一个 Long 的属性,如果它不是毫秒,请确保定义单位(使用 @DurationUnit )。 这样做提供了一个透明的升级路径,同时支持更丰富的格式

转换为期间(Period)

除了duration,Spring Boot还可以使用 java.time.Period 类型。 以下格式可以在application properties中使用。

  • 一个常规的 int 表示法(使用天作为默认单位,除非指定了 @PeriodUnit )。
  • 标准的ISO-8601格式 由 java.time.Period 使用。
  • 一个更简单的格式,其中值和单位对是耦合的( 1y3d 表示1年3天)。

支持下列简单的单位格式。

  • y 年
  • m 月
  • w 周
  • d 日

java.time.Period 类型实际上从未存储过周数,它是一个快捷方式,意味着 “7天”。

转换为数据大小(Data Sizes)

Spring Framework有一个 DataSize 值类型,以字节为单位表达大小。 如果你公开了一个 DataSize 属性,application properties中的以下格式就可用。

  • 一个常规的 long 表示(使用字节作为默认单位,除非指定了 @DataSizeUnit)。
  • 一个更易读的格式,其中值和单位是耦合的(10MB 意味着10兆字节)。

考虑以下例子。

Java

Kotlin

@ConfigurationProperties("my")
public class MyProperties {

    @DataSizeUnit(DataUnit.MEGABYTES)
    private DataSize bufferSize = DataSize.ofMegabytes(2);

    private DataSize sizeThreshold = DataSize.ofBytes(512);

    // getters/setters...

}

要指定一个10兆字节(Mb)的缓冲区大小, 10 和 10MB 是等价的。 256字节的大小阈值可以指定为 256 或 256B。

你也可以使用如下这些支持的单位。

  • B 字节
  • KB KB
  • MB MB
  • GB GB
  • TB TB

默认单位是字节,可以使用 @DataSizeUnit 来重写,如上面的例子所示。

如果你喜欢使用构造函数绑定,同样的属性可以被暴露出来,如下面的例子所示。

Java

@ConfigurationProperties("my")
public class MyProperties {

    // fields...

    public MyProperties(@DataSizeUnit(DataUnit.MEGABYTES) @DefaultValue("2MB") DataSize bufferSize,
            @DefaultValue("512B") DataSize sizeThreshold) {
        this.bufferSize = bufferSize;
        this.sizeThreshold = sizeThreshold;
    }

    // getters...

}

如果你正在升级一个 Long 属性,确保定义单位(使用 @DataSizeUnit),如果它不是字节。 这样做提供了一个透明的升级路径,同时支持更丰富的格式。 

九、@ConfigurationProperties 校验

只要使用Spring的 @Validated 注解,Spring Boot就会尝试验证 @ConfigurationProperties 类。 你可以直接在你的配置类上使用JSR-303的 jakarta.validation 约束注解。 要做到这一点,请确保你的classpath上有一个兼容的JSR-303实现,然后将约束注解添加到你的字段中,如下面的例子所示。

Java

@ConfigurationProperties("my.service")
@Validated
public class MyProperties {

    @NotNull
    private InetAddress remoteAddress;

    // getters/setters...

}

你也可以通过在 configuration properties 的 @Bean 方法上注解 @Validated 来触发验证。 

为了确保总是为嵌套的属性触发验证,即使没有找到属性,相关的字段必须用 @Valid 来注释。 下面的例子建立在前面的 MyProperties 的基础上。

Java

@ConfigurationProperties("my.service")
@Validated
public class MyProperties {

    @NotNull
    private InetAddress remoteAddress;

    @Valid
    private final Security security = new Security();

    // getters/setters...

    public static class Security {

        @NotEmpty
        private String username;

        // getters/setters...

    }

}

你也可以通过创建一个名为 configurationPropertiesValidator 的bean定义来添加一个自定义的Spring Validator。 @Bean 方法应该被声明为 static。 配置属性验证器是在应用程序生命周期的早期创建的,将 @Bean 方法声明为静态,可以让Bean的创建不需要实例化 @Configuration 类。 这样做可以避免过早实例化可能引起的任何问题。

spring-boot-actuator 模块包括一个暴露所有 @ConfigurationProperties Bean 的端点。 你可以通过浏览器访问 /actuator/configprops 或使用相应的JMX端点。 详情见"生产就绪"部分。

十、@ConfigurationProperties vs. @Value

@Value 注解是一个核心的容器功能,它不提供与类型安全的配置属性相同的功能。 下表总结了 @ConfigurationProperties 和 @Value 所支持的功能。

功能

@ConfigurationProperties

@Value

宽松绑定

Yes

有限制 (见 下文注释)

支持 Meta-data

Yes

No

SpEL 表达式

No

Yes

如果你确实想使用 @Value,我们建议你使用属性名称的规范形式(仅使用小写字母的kebab-case)来引用属性名称。 这将允许Spring Boot使用与 宽松绑定 @ConfigurationProperties 时相同的逻辑。

例如,@Value("${demo.item-price}") 将从 application.properties 文件中获取 demo.item-price 和 demo.itemPrice 形式,以及从系统环境中获取 DEMO_ITEMPRICE。 如果你用 @Value("${demo.itemPrice}") 代替,demo.item-price 和 DEMO_ITEMPRICE 将不会被考虑。

如果你为你自己的组件定义了一组配置键,我们建议你将它们分组在一个用 @ConfigurationProperties 注解的POJO中。 这样做将为你提供结构化的、类型安全的对象,你可以将其注入到你自己的bean中。

来自应用application property 文件的 SpEL 表达式在解析这些文件和填充environment时不会被处理。 然而,可以在 @Value 中写一个 SpEL 表达式。 如果来自应用程序属性文件的属性值是一个 SpEL 表达式,它将在被 @Value 消费时被解析。

Supongo que te gusta

Origin blog.csdn.net/leesinbad/article/details/131970671
Recomendado
Clasificación