文章目录
- 1、@ConfigurationProperties自定义Bean属性绑定
- 2、@EnableConfigurationProperties注解
- 3、@ConfigurationProperties第三方Bean属性绑定
- 4、松散绑定
- 5、常用计量单位
- 6、数据校验
- 7、yaml绑定值的坑--关于进制
1、@ConfigurationProperties自定义Bean属性绑定
前面读取yaml文件配置时,用过这个注解,先复习下它的用法。首先在yml配置文件中定义个属性:
# spring默认在用server,我加个s刻意回避下,别影响到服务启动
servers:hostAddr: http://127.0.0.1port: 9527timeout: 6000
定义实体类接收这个参数:
OData
@Component //首先它得是受Spring管控的对象,即Bean,不然我哪怕拿到值,我怎么联系你给你
@ConfigurationProperties("servers")
public class ServerInfo {private String hostAddr:private int port:private long timeout;
}
接下来看下效果,懒得写UT,再获取IoC容器对象了 ,直接借用启动类run方法返回的IoC对象来获取上面这个Bean:
@SpringBootApplication
public class MyApplication{public static void main(String[] args){ConfigurableApplicationContext applicationContext = SpringApplication.run(MyApplication.class,args);ServerInfo bean = applicationContext.getBean(ServerInfo.class);System.out.printin(bean);}
}
成功:
@ConfigurationProperties中写你要加载的属性的上一层级的
,如果上一层还有父级,则xxx.xx就行。最后,@ConfigurationProperties注解使用时可能有warn信息:
要解除使用@ConfigurationProperties注释警告,引入以下这个依赖然后IDEA中点Hide隐藏就行:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
2、@EnableConfigurationProperties注解
有个关联知识点:@EnableConfigurationProperties注解
,修改上面的代码,启动类上加@EnableConfigurationProperties注解:
@SpringBootApplication
@EnableConfigurationProperties(ServerInfo.class)
public class MyApplication{public static void main(String[] args){ConfigurableApplicationContext applicationContext = SpringApplication.run(MyApplication.class,args);ServerInfo bean = applicationContext.getBean(ServerInfo.class);System.out.printin(bean);}
}
此时,重启服务报错:excepted single matching bean but found 2
这里的原因是@EnableConfigurationProperties(ServerInfo.class)指定了ServerInfo.class,就会把这个类的Bean加载进来,而之前ServerInfo类中又用@Component注册了一次。解决报错把@Component注释掉就好。因此:
@EnableConfigurationProperties注解不能与@Component注解同时使用!
@ConfigurationProperties和@EnableConfigurationProperties,前者是做属性绑定的,后者是开启属性绑定,并设定对应的目标是谁。
@EnableConfigurationProperties(ServerInfo.class)
后者的好处是可以通过这一行代码清晰看到都有哪些类从yml中读取了属性,使得对于这种类的管理不松散。
3、@ConfigurationProperties第三方Bean属性绑定
以上是给我们自定义的Bean注入属性,那第三方Bean呢?@ConfigurationProperties也可以实现。先写个测试的yml配置:
datasource:driverClassName: com.mysql.hhhh # 我只是测拿数据,不连数据库,驱动随便写
再定义第三方Bean,@SpringBootApplication注解本身往下追就有@Configuration注解,所以这里直接在启动类里定义第三方Bean
@SpringBootApplication
public class MyApplication{@Bean@ConfigurationProperties(prefix = "datasource")public DruidDataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();return dataSource;}public static void main(String[] args){ConfigurableApplicationContext applicationContext = SpringApplication.run(MyApplication.class,args);DruidDataSource bean = applicationContext.getBean(DruidDataSource.class);System.out.printin(bean);System.out.printin(bean.getDriverClassName());}
}
运行,属性绑定成功:
4、松散绑定
@ConfigurationProperties绑定属性支持属性名宽松绑定 ,即:
OData
@Component
@ConfigurationProperties("servers")
public class ServerInfo {private String ipAddress:private int port:private long timeout;
}
属性的名字和配置文件的字段不用一模一样,以下配置都是生效的:
- 驼峰
servers:ipAddress: 192.168.1.1port: 2345 timeout: -1
- 下划线
servers:ip_address: 192.168.1.2port: 2345timeout: -1
- 中划线(烤肉串写法,形似 00-0-0-0—,推荐写法)
servers:ip-address: 192.168.1.2port: 2345timeout: -1
- 常量模式
servers:IP_ADDRESS: 192.168.1.2port: 2345timeout: -1
- 随便加下划线或者中划线
servers:ip-ad-d_rEss: 192.168.1.2Port: 2345timeout: -1
当然实体类中的属性名也一样:
public class ServerInfo {private String ipADDRESS:private int port:private long timeout;
}
但@ConfigurationProperties注解的prefix属性,前缀名必须符合命名规范,即仅能使用纯小写字母、数字、下划线作为合法的字符,大写都不行。此外,@Value注解不支持宽松绑定,大小写不一样就会解析失败。
5、常用计量单位
SpringBoot支持JDK8提供的时间与空间计量单位,@DurationUnit和@DataSizeUnit注解标明所在属性的值的单位。还是上面的例子,加个属性serverTimeOut做调试:
servers:ipAddress: 192.168.1.1port: 2345 timeout: -1serverTimeOut: 6
此时, serverTimeOut值6的单位是不确定的,实体类中使用一个时间类Duration来接收:
OData
@Component
@ConfigurationProperties("servers")
public class ServerInfo {private String ipAddress:private int port:private long timeout;private Duration serverTimeOut;
}
打印这个Bean,可以看到0.06s,即默认为ms:
接下来加注解指定这个属性的单位:
...
@DurationUnit(ChronoUnit.MINUTES)
private Duration serverTimeOut;
...
同理,还有空间单位,默认单位Byte,可加@DataSizeUnit注解指定:
OData
@Component
@ConfigurationProperties("servers")
public class ServerInfo {private String ipAddress:private int port:private long timeout;@DurationUnit(ChronoUnit.MINUTES)private Duration serverTimeOut;@DataSizeUnit(DataUnit.MEGABYTES)private DataSize dataSize;
}
6、数据校验
开启数据校验有助于系统安全性,J2EE规范中JSR303规范定义了一组有关数据校验相关的API,先导入JSR303的依赖坐标:
<dependency> <groupId>javax.validation</groupId><artifactId>validation-api</artifactId>
</dependency>
然后在需要校验的地方开启数据校验:
//springframework下的
@Valiated
然后给属性加具体的校验规则,相关注解有:
此时,运行出现报错:
报错信息为找不到具体的实现,这就和JDBC和mysql驱动是一个意思,有接口,代码能写,但一运行,没有实现,跑不起来。再引入JSR303校验框架的实现,如Hibernate:
<dependency> <groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId>
</dependency>
再运行,校验成功:
JSR303的校验,用处很多,比如写接口时,对前端的传参做校验,只需要在Dto类中的属性加相关注解即可,如:
添加校验规则:
7、yaml绑定值的坑–关于进制
在yaml中定义一个属性password,取值0127,使用属性绑定或者@Value取值,打印这个值:
问题的原因就是,在yaml中,书写数字和简单字符串都不用加引号,而0127又特殊在以0开头,后面的字符在0-7之间,被当作了八进制,可通过加引号解决:
datasource:password: "0127"
即:注意yaml文件中对于数字的定义支持进制书写格式,如需使用字符串请使用引号明确标注