首页 > 其他分享 >【Spring Boot 丨类型安全配置属性 】

【Spring Boot 丨类型安全配置属性 】

时间:2023-08-05 10:32:59浏览次数:32  
标签:String Spring 绑定 Boot Security 属性 public 构造函数

本篇来讲一讲 外部化配置类型安全属性

(类型安全配置属性)

在这里插入图片描述

类型安全配置属性


  使用@Value("${property}")注释来注入配置属性有时可能很麻烦,尤其是处理多个属性或您的数据本质上是层次结构的情况下。Spring Boot 提供了另一种使用属性的方法,让强类型 bean 管理和验证应用程序的配置。

JavaBean 属性绑定


import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

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

    private boolean enabled;

    private InetAddress remoteAddress;

    private final Security security = new Security();

    public boolean isEnabled() {
        return this.enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public InetAddress getRemoteAddress() {
        return this.remoteAddress;
    }

    public void setRemoteAddress(InetAddress remoteAddress) {
        this.remoteAddress = remoteAddress;
    }

    public Security getSecurity() {
        return this.security;
    }

    public static class Security {

        private String username;

        private String password;

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

        public String getUsername() {
            return this.username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return this.password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public List<String> getRoles() {
            return this.roles;
        }

        public void setRoles(List<String> roles) {
            this.roles = roles;
        }

    }

}


POJO 定义了以下属性:

  • my.service.enabled,默认值为false。
  • my.service.remote-address,具有可以从 强制的类型String。
  • my.service.security.username,带有一个嵌套的“安全”对象,其名称由属性名称确定。特别是,该类型根本没有在那里使用,并且本来可以使用SecurityProperties。
  • my.service.security.password。
  • my.service.security.roles,其中的集合String默认为USER。

注意:   映射到 Spring Boot 中可用的@ConfigurationProperties类的属性(通过属性文件、YAML 文件、环境变量和其他机制进行配置)是公共API,但类本身的访问器(getter/setter)并不意味着可以直接使用。

你需要使用 @EnableConfigurationProperties 注解将属性类注入配置类中。

@Configuration
@EnableConfigurationProperties(MyProperties.class)
public class MyConfiguration {
}

注意:   这种安排依赖于默认的空构造函数,并且 getter 和 setter 通常是强制性的,因为绑定是通过标准 Java Beans 属性描述符进行的,就像在 Spring MVC中一样。在以下情况下可以省略 setter:

  • 映射,只要它们被初始化,就需要一个 getter,但不一定需要一个 setter,因为它们可以被绑定器改变。
  • m可以通过索引(通常使用 YAML)或使用单个逗号分隔值(属性)来访问集合和数组。在后一种情况下,setter 是强制性的。我们建议始终为此类类型添加 setter。如果初始化集合,请确保它不是不可变的(如前面的示例所示)。
  • 如果嵌套 POJO 属性已初始化(如前面示例中的Security字段),则不需要 setter。如果您希望绑定器使用默认构造函数动态创建实例,则需要一个setter。

  有些人使用 Project Lombok 自动添加 getter 和 setter。确保 Lombok不会为此类类型生成任何特定的构造函数,因为容器会自动使用它来实例化对象。

  最后,仅考虑标准 Java Bean 属性,并且不支持静态属性的绑定。

构造函数绑定


上面的示例可以以不可变的方式重写,示例如下:

import java.net.InetAddress;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;

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

    private final boolean enabled;

    private final InetAddress remoteAddress;

    private final Security security;

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

    public boolean isEnabled() {
        return this.enabled;
    }

    public InetAddress getRemoteAddress() {
        return this.remoteAddress;
    }

    public Security getSecurity() {
        return this.security;
    }

    public static class Security {

        private final String username;

        private final String password;

        private final List<String> roles;

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

        public String getUsername() {
            return this.username;
        }

        public String getPassword() {
            return this.password;
        }

        public List<String> getRoles() {
            return this.roles;
        }

    }

}

  在此设置中,单个参数化构造函数的存在意味着应使用构造函数绑定。这意味着绑定器将找到一个带有您希望绑定的参数的构造函数。如果您的类有多个构造函数,则可以使用@ConstructorBinding注释来指定用于构造函数绑定的构造函数。要选择退出具有单个参数化构造函数的类的构造函数绑定,该构造函数必须使用@Autowired 进行注释。

  构造函数绑定可以与记录一起使用。除非您的记录有多个构造函数,否则无需使用@ConstructorBinding。

  构造函数绑定类的嵌套成员(例如上面的示例Security)也将通过其构造函数进行绑定。

  可以使用@DefaultValue 在构造函数参数和记录组件指定默认值。转换服务将用于将注释的String值强制转换为缺失属性的目标类型。

  参考前面的示例,如果没有属性绑定到Security,则MyProperties实例将包含null的值。要使其包含非空security实例,即使没有绑定任何属性(使用 Kotlin 时,这将要求Security 的username和password参数声明为可为空,因为它们没有默认值),请使用空的@DefaultValue注释:

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

注意:   要使用构造函数绑定,必须使用@EnableConfigurationProperties或配置属性扫描来启用类。您不能将构造函数绑定到由常规Spring 机制创建的 bean(例如@Componentbean、使用@Bean方法创建的 bean 或使用 @Import加载的bean )。    要在本机映像中使用构造函数绑定,必须使用-parameters编译类。 如果您使用 Spring Boot 的Gradle 插件或者使用 Maven 和spring-boot-starter-parent,将会自动编译。   在java,util 中不建议使用@ConfigurationProperties,因为它主要用作返回类型。因此,它不太适合配置属性注入。为了与其他类型的属性保持一致,如果声明了一个Optional属性并且它没有值,则将绑定null,而不是空的Optional。

松散的绑定规则

  Spring Boot 使用一些宽松的规则将Environment属性绑定到bean,因此属性名称和 bean 属性名称@ConfigurationProperties之间不需要完全匹配。Environment此功能有用的常见示例包括用破折号分隔的环境属性(例如,context-path绑定到contextPath)和大写的环境属性(例如,PORT绑定到port)。 示例如下:

import org.springframework.boot.context.properties.ConfigurationProperties;

@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;
    }

}

松散的绑定:

Property Note
my.main-project.person.first-name 建议使用在.properties 和 YAML 文件。- 分隔
my.main-project.person.firstName 标准的驼峰大小写语法。
my.main-project.person.first_name 下划线_ 在.properties 和 YAML 文件 使用的另一种格式
my.main-project.person.first_name 大写格式, 推荐在使用环境系统变量时使用。

每个属性源的松散绑定规则:

Property Source Simple List
Properties Files 驼峰式大小写、烤肉串大小写或下划线表示法 使用[ ] 或 逗号分隔值的标准列表语法
YAML Files 驼峰式大小写、烤肉串大小写或下划线表示法 标准 YAML 列表语法或逗号分隔值
Environment Variables 大写格式,下划线作为分隔符 用下划线包围的数值
System properties 驼峰式大小写、烤肉串大小写或下划线表示法 使用[ ] 或 逗号 分隔值的标准列表语法

属性转换


  Spring Boot 在绑定到@ConfigurationPropertiesbean 时尝试将外部应用程序属性强制转换为正确的类型。

  如果需要类型转换,你可以提供一个 ConversionService bean (一个名叫 conversionService 的 bean) 或自定义属性配置 (一个 CustomEditorConfigurer bean) 或自定义的 Converters (带有@ConfigurationPropertiesBinding 注解修饰的 bean)。

注: 由于此 bean 在应用程序生命周期的早期就被请求,因此请确保限制您ConversionService正在使用的依赖项。通常,您需要的任何依赖项在创建时可能不会完全初始化。如果配置键强制不需要ConversionService ,并且仅依赖于使用@ConfigurationPropertiesBinding限定的自定义转换器,您可能需要重命名您的自定义ConversionService 。

在这里插入图片描述

  如果喜欢的话,欢迎 

标签:String,Spring,绑定,Boot,Security,属性,public,构造函数
From: https://blog.51cto.com/u_16111319/6973742

相关文章

  • Springboot 3.x 集成Knife4j [踩坑日记]
    之前项目用的是SpringBoot2.x新项目用了SpringBoot3.x版本,引入Knife4j报错java.lang.TypeNotPresentException:Typejavax.servlet.http.HttpServletRequestnotpresent,以为是servlet的原因,更新了Servlet的版本,依旧报错,几番周折找到找到了在SpringBoot3中集成Knife......
  • Vue进阶(幺肆幺):Vue 计算属性 computed 方法内传参
    (文章目录)一、前言在前期博文《Vue进阶(八十四):vue中Computed和Watch的使用和区别》中,讲解了vue中Computed和Watch的使用和区别,其中,只是介绍了computed如何计算元素属性,并未介绍如何方法传参。本篇博文主要讲解下如何利用computed的计算属性进行传参。二、场景引入在前端项......
  • BootstrapBlazor组件库,Menu组件NavLinkMatch导致的多个菜单项被被同时选中
    BootstrapBlazor组件库,Menu组件NavLinkMatch导致的多个菜单项被被同时选中BootstrapBlazor版本更新到7.9.0后,Menu组件出现首页同时被选中的情况默认首页/路径是选中状态,但是当选中其他路径后,首页路径还是选中状态。这是因为在BootstrapBlazor组件最新版中支持了一个新特性。可......
  • Spring Boot 数据库连接池性能优化
    当涉及到SpringBoot中的性能优化时,连接池是一个非常重要的话题。连接池在数据库访问和其他外部资源访问中扮演着关键角色,可以显著提升应用程序的性能和资源利用率。在本文中,我们将深入探讨如何在SpringBoot应用中优化数据库连接池的配置,从而提升应用性能。数据库连接池是管理......
  • Spring Boot 微服务架构中的服务发现和注册
    当涉及到SpringBoot中的微服务架构时,服务发现和注册是一个至关重要的话题。在微服务架构中,各个服务需要相互通信,而服务发现和注册机制则允许服务动态地发现和定位其他服务,从而实现更好的弹性和可扩展性。在本文中,我们将深入探讨如何在SpringBoot中实现服务发现和注册,以及如何......
  • Spring Boot 中的 AOP 实践
    在SpringBoot中使用AOP(面向切面编程)可以帮助您在应用程序中更优雅地处理横切关注点,如日志、事务管理和安全性。本文将深入探讨如何在SpringBoot中使用AOP,以及如何创建自定义切面来实现特定功能。1.什么是AOP?AOP是一种编程范式,它允许您将横切关注点(如日志、安全性、事务......
  • Spring Boot 中的缓存优化
    在SpringBoot中使用缓存可以显著提升应用程序的性能和响应时间。通过合理地配置缓存,可以减少对数据库或其他外部资源的频繁访问,从而提升系统的吞吐量和性能。本文将深入探讨如何在SpringBoot中使用缓存,以及如何优化缓存配置以获得最佳性能。1.为什么使用缓存?使用缓存可以将......
  • Spring Boot 中的数据库连接池
    在SpringBoot中,使用数据库连接池是优化应用性能和资源利用的重要手段。数据库连接池允许应用程序重复使用预先创建的数据库连接,避免了频繁地创建和关闭连接,从而提升了数据库访问的效率。本文将深入探讨在SpringBoot中使用数据库连接池的优势和配置方法。1.数据库连接池的优......
  • springboot 关于servlet容器配置修改 组件注册 容器切换 使用外部tomcat
    1.嵌入式Servlet容器配置修改1.通过全局配置文件修改可以通过server.xxx来进行web服务配置,没有带服务器名称的则是通用配置通过带了具体的服务器名称则是单独对该服务器进行设置,比如server.tomcat.xxx就是专门针对tomcat的配置2.通过WebServerFactoryCus......
  • SpringCloud微服务架构
    微服务框架单体架构单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部署。优点:架构简单部署成本低缺点:耦合度高(维护困难、升级困难)分布式架构分布式架构:根据业务功能对系统进行拆分,每个业务模块作为独立项目开发,称为一个服务。优点:降低服务耦合......