SpringBoot进阶-第三方bean属性绑定

一、基础绑定

1、@ConfigurationProperties注解

@ConfigurationProperties 注解用于将 bean 中的成员属性与配置文件中的属性进行绑定

可以注解在类上或方法上

自定义 bean

类上注解 @Component 与 @ConfigurationProperties 即可

例如 yaml 配置文件中有如下配置:

test-bean:
  ipaddress: 127.0.0.1
  port: 8080

有如下 TestBean:

@Data
@Component
@ConfigurationProperties(prefix = "test-bean")
// @ConfigurationProperties("test-bean")	// 默认即为 prefix 属性指定
public class TestBean {
    
    
    private String ipAddress;
    private int    port;
}

@ConfigurationProperties 注解的 prefix 属性用于指定绑定配置中的属性

可以在启动类中获取 applicationContext 之后获取 bean 来查看效果:

@SpringBootApplication
public class Application {
    
    
    public static void main(String[] args) {
    
    
        ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
        TestBean bean = applicationContext.getBean(TestBean.class);
        System.out.println(bean);
        // 输出:TestBean(ipAddress=192.168.100.100, port=8088)
    }
}

解决报错

在 idea 中,自定义的 bean 注解 @ConfigurationProperties 可能会有以下错误

在这里插入图片描述不影响程序运行

如果不想见到可以引入下面的依赖,即可解决

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>

第三方 bean

配置类中写一个返回该 bean 的方法,并在方法上注解 @Bean 与 @ConfigurationProperties 即可

以 Druid 连接池中的 DruidDataSource 为例

注意导入 druid 依赖而非 druid-spring-boot-starter

yaml 配置如下:

datasource:
  driver-class-name: com.mysql.cj.jdbc.Driver

我们将启动类作为配置类来测试:

@SpringBootApplication
public class Application {
    
    
    @Bean
    @ConfigurationProperties(prefix = "datasource")
    public DruidDataSource druidDataSource() {
    
    
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("noting");
        return dataSource;
    }

    public static void main(String[] args) {
    
    
        ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);

        DruidDataSource dataSource = applicationContext.getBean(DruidDataSource.class);
        System.out.println(dataSource.getDriverClassName());
		// 输出:com.mysql.cj.jdbc.Driver
    }
}

注意 @Bean 方法里对属性 set 不会影响配置文件中的配置

如上例中,方法内调用了 setDriverClassName 方法,但输出的依然是 yaml 配置中的属性值

可以把 @Bean 方法中的 set 方法给定的值当作默认配置,而 yaml 文件中的是最终配置

2. @EnableConfigurationProperties 注解

@EnableConfigurationProperties 注解在配置类或启动类上,用于指定开启绑定的类,多个类用数组

其效果与 bean 上注解 @Component 相同,但两者不能同时对一个 bean 生效,会因为找到两个相同的 bean 而报错

@EnableConfigurationProperties 添加的类,类上必须有 @ConfigurationProperties 注解

@EnableConfigurationProperties 与 @Bean 注解的方法不会产生关联

TestBean 示例如下:

@Data
//@Component
@ConfigurationProperties(prefix = "test-bean")
public class TestBean {
    
    
    // ...
}

启动类:

@SpringBootApplication
@EnableConfigurationProperties({
    
    TestBean.class})
public class Application {
    
    
    public static void main(String[] args) {
    
    
        ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
        TestBean bean = applicationContext.getBean(TestBean.class);
        System.out.println(bean);
    }
}

二、松散绑定

松散绑定(或宽松绑定),指绑定属性时不必严格与属性名一致

在 @ConfigurationProperties 注解中,可以添加任意的中划线 “-”,但不能中划线开头,不能包含大写字母,事实上只能使用小写字母和中划线

在 yaml 配置文件中,属性名可以添加任意的 中划线 “-”,下划线 “_”,空格,不影响绑定的匹配

示例下:

TestBean:

@Component
@ConfigurationProperties(prefix = "test-bean")	// 可添加任意的 '-',但不可符号开头,也不可含大写字母
@Data
public class TestBean {
    
    
    private String ipAddress;	// 变量名也可添加 '_'
}

yaml:

# 以下均可正常匹配
testbean:
  ip-address: 192.168.0.101		# 烤肉串格式(官方推荐)
  ip_address: 192.168.0.102		# 下划线格式
  IP_ADDRESS: 192.168.0.103 	# 常量格式,大写与下划线
  "ip address": 192.168.0.104 	# 空格或双引号也是可以的
  -_iPa_d d-- Re ss: 192.168.0.105 	# 乱七八糟,只要字母可匹配就能生效

官方推荐的格式是烤肉串格式,如果存在多个可匹配的属性时,只有烤肉串格式的生效

另外,据黑马李老师所讲,@Value 注入属性值时,不支持松散匹配

但我个人测试时是可以的,测试类如下:

@SpringBootTest
class ApplicationTests {
    
    

    @Value("${mytest.message}")
    private String message;

    @Test
    void contextLoads() {
    
    
        System.out.println(message);
        // 输出:Hello world!!
    }
}

yaml文件如下:

my-test:
  _MESSAGE-: Hello world!!

@Value 中只要不含 中划线和小写字母以外 的符号即可

三、常用计量单位

Duration 表示一段时间,如 3分钟,5小时

DataSize 表示文件大小,如 10B,5MB

这样的属性在配置的时候可以指定单位

如下:

@Component
@ConfigurationProperties(prefix = "test-bean")
@Data
public class TestBean {
    
    
	// 指定默认时间单位,未设置则为毫秒 ms
    @DurationUnit(ChronoUnit.SECONDS)
    private Duration serverTimeout;
	// 指定文件单位,未设置则为字节 B
    @DataSizeUnit(DataUnit.KILOBYTES)
    private DataSize dataSize;
}

yaml 配置文件:

test-bean:
  server-timeout: 3ms	#只支持天以内的单位:ms, s, m, h, d
  data-size: 10B		#必须大写:B, KB, MB, GB, TB

四、属性校验

举例,端口号的设定范围是 0 ~ 65535,我们希望启动时对配置进行校验

  1. 引入 validation-api 和 hibernate-validator 两个依赖

validation-api 提供接口,而 hibernate-validator 提供实现

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
</dependency>
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>
  1. bean 上注解 @Validated
  2. 属性上注解校验规则

示例如下:

@Data
@Component
@Validated
@ConfigurationProperties(prefix = "test-bean")
public class TestBean {
    
    

    @Max(value = 65535, message = "最大端口号为 65535")
    @Min(value = 0, message = "最小端口号为 0")
    private int port;

}

在 javax.validation.constraints 包内还有其它可以自定义的规则,可以自己研究下

在这里插入图片描述

五、进制转换规则

yaml 文件中配置纯数字可能会导致结果不合预期,如下示例:

yaml 配置:

my-test:
  password: 012345

测试类:

@SpringBootTest
class ApplicationTests {
    
    

    @Value("${my-test.password}")
    private String password;

    @Test
    void contextLoads() {
    
    
        System.out.println(password);
        // 输出:5349
    }
}

可以发现 password 的值配置的是 012345,结果却变成了5349

这是因为 012345 触发了八进制的转换格式

0 开头且所以数字小于8,便会被当作八进制转为十进制,然后被注入到属性

同样还有,0b 开头为二进制,0x 开头为十六进制

如 0b_0101_0101 和 0x3f3f3f3f

建议字符串类型的属性用双引号括住比较好,尤其密码类的难以排查原因

猜你喜欢

转载自blog.csdn.net/Cey_Tao/article/details/127584000