Spring Boot之ConfigurationProperties与Value

Stella981
• 阅读 617

#Spring Boot之ConfigurationProperties与Value#

使用@Value("${property}")注入到你配置中有时是笨重的,特别是你有多个配置文件或者你的数据是多层次的。Spring Boot提供了另一个种允许强类型方法让你去管理和校验你的配置

package com.moregx;

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

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

@ConfigurationProperties("foo")
public class FooProperties {

    private boolean enabled;

    private InetAddress remoteAddress;

    private final Security security = new Security();

    public boolean isEnabled() {
        return enabled;
    }

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

    public InetAddress getRemoteAddress() {
        return remoteAddress;
    }

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

    public Security getSecurity() {
        return security;
    }
    
    public class Security {

        private String username;

        private String password;

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

        public String getUsername() {
            return username;
            }
    
            public void setUsername(String username) {
                this.username = username;
            }
    
            public String getPassword() {
                return password;
            }
    
            public void setPassword(String password) {
                this.password = password;
            }
    
            public List<String> getRoles() {
                return roles;
            }
    
            public void setRoles(List<String> roles) {
                this.roles = roles;
            }
            
            
            
    
        }
    
        
    }

上面这个POJO定义了以下几个properties:

  • foo.enabled,默认为false
  • foo.remote-address,可以从String强转
  • foo.security.username
  • foo.security.password
  • foo.security.roles

注: Getters 和 setters通常是强制要求的,因为像在Spring MVC中一样,是通过标准的Java Beans property descriptors来绑定的.但是在有些情况下,setter是可以忽略的:

  • Maps,因为它们在初始化的时候,需要getter,但是不需要setter,因为他们可以被binder转换的
  • Collections 和 arrays可以通过index或者使用逗号分隔符。setter是必要的,建议你在这些类型中加一个setter,如果你初始化一个集合,确认它不是不可变的
  • 如果嵌套的POJO属性初始化,setter是不需要的

你还需要列出的属性类注册在@EnableConfigurationProperties中:

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

即使这个configuration将会为FooProperties创建一个正常的bean,我们也建议 @ConfigurationProperties只处理环境的问题,特别是从上下文中不注入其他bean的时候.话虽如此,@EnableConfigurationProperties注解也会自动用于项目以确保任何被@ConfigurationProperties注解的bean都会被环境配置。

@Component
@ConfigurationProperties(prefix="foo")
public class FooProperties {

    // ... see above

}

第三方配置

像把@ConfigurationProperties注解到一个类上一样,你也可以在@Bean方法上使用它。。当你需要绑定属性到不受你控制的第三方组件时,这种方式非常有用。

为了从Environment属性配置一个bean,将@ConfigurationProperties添加到它的bean注册过程:

@ConfigurationProperties(prefix = "bar")
@Bean
public BarComponent barComponent() {
    ...
}

所有以bar开头的属性都会被映射到BarComponent

松散绑定

Spring Boot使用了一些松散的规则用于把环境属性绑定到@ConfigurationProperties上,所以不需要精确字符匹配环境属性名称和bean属性名称.在使用虚线分割和大小写的时候是很用的。

例如,下面这个@ConfigurationProperties类:

@ConfigurationProperties(prefix="person")
public class OwnerProperties {

    private String firstName;

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

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

}

下面这些名称都是可以的:

person.firstName     标准的驼峰式大小写语法。
person.first-name   虚线
person.first_name   下划线
PERSON_FIRST_NAME    大写,建议使用在环境变量中

属性转换

当绑定 @ConfigurationProperties bean的时候,Spring会尝试转换属性为正确的类型。如果你需要定制化类型,你要提供一个ConversionService bean或者一个通过CustomEditorConfigurer bean提供一个自定义属性编辑,或者自定义转换器。

@ConfigurationProperties 校验

Spring Boot会对加上 @Validated 注解的 @ConfigurationProperties的类做校验。默认使用JSR-303,你可以轻松的为你的@ConfigurationProperties类添加JSR-303 javax.validation约束注解:

@ConfigurationProperties(prefix="foo")
@Validated
public class FooProperties {

    @NotNull
    private InetAddress remoteAddress;

    // ... getters and setters

}

如果校验嵌套属性的话,你要在字段加 @Valid,例如上面那个例子:

@ConfigurationProperties(prefix="foo")
@Validated
public class FooProperties {

    @NotNull
    private InetAddress remoteAddress;

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

    // ... getters and setters

    public static class Security {

        @NotEmpty
        public String username;

        // ... getters and setters

    }

}

@ConfigurationProperties 和 @Value 的对比###

特性                    @ConfigurationProperties                    @Value     

松散绑定                    支持                                    不支持

Meta-data support           支持                                    支持

SpEL表达式                    不支持                                     支持

如果你在你的组件里定义了多个configuration key,我们建议你把他们放到一个@ConfigurationProperties POJO对象里面。因为@Value不支持relaxed binding,所有当你使用环境变量的时候,@Value并不是一个好的选择。

示例:https://github.com/RobinFenng/springboot-samples/tree/master/springboot-samples-typesafe

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Karen110 Karen110
3年前
​一篇文章总结一下Python库中关于时间的常见操作
前言本次来总结一下关于Python时间的相关操作,有一个有趣的问题。如果你的业务用不到时间相关的操作,你的业务基本上会一直用不到。但是如果你的业务一旦用到了时间操作,你就会发现,淦,到处都是时间操作。。。所以思来想去,还是总结一下吧,本次会采用类型注解方式。time包importtime时间戳从1970年1月1日00:00:00标准时区诞生到现在
Stella981 Stella981
3年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Easter79 Easter79
3年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Stella981 Stella981
3年前
CAS 实现站内单点登录及实现第三方 OAuth、OpenId 登录(四)
一、OAuth配置1.配置OAuth提供商<bean id"weibo" class"com.buession.oauth.provider.impl.WeiboProvider"    <property name"key" value"the_key_for_
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这