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


    一、基础绑定

    1、@ConfigurationProperties注解

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

    可以注解在类上或方法上

    自定义 bean

    类上注解 @Component 与 @ConfigurationProperties 即可

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

    test-bean:
      ipaddress: 127.0.0.1
      port: 8080
    
    • 1
    • 2
    • 3

    有如下 TestBean:

    @Data
    @Component
    @ConfigurationProperties(prefix = "test-bean")
    // @ConfigurationProperties("test-bean")	// 默认即为 prefix 属性指定
    public class TestBean {
        private String ipAddress;
        private int    port;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    @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)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    解决报错

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

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

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

    <dependency>
    	<groupId>org.springframework.bootgroupId>
    	<artifactId>spring-boot-configuration-processorartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    第三方 bean

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

    以 Druid 连接池中的 DruidDataSource 为例

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

    yaml 配置如下:

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

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

    @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
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    注意 @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 {
        // ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    启动类:

    @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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    二、松散绑定

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

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

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

    示例下:

    TestBean:

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

    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 	# 乱七八糟,只要字母可匹配就能生效
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

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

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

    @SpringBootTest
    class ApplicationTests {
    
        @Value("${mytest.message}")
        private String message;
    
        @Test
        void contextLoads() {
            System.out.println(message);
            // 输出:Hello world!!
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    yaml文件如下:

    my-test:
      _MESSAGE-: Hello world!!
    
    • 1
    • 2

    @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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    yaml 配置文件:

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

    四、属性校验

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

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

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

    <dependency>
        <groupId>javax.validationgroupId>
        <artifactId>validation-apiartifactId>
    dependency>
    <dependency>
        <groupId>org.hibernate.validatorgroupId>
        <artifactId>hibernate-validatorartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    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;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

    在这里插入图片描述

    五、进制转换规则

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

    yaml 配置:

    my-test:
      password: 012345
    
    • 1
    • 2

    测试类:

    @SpringBootTest
    class ApplicationTests {
    
        @Value("${my-test.password}")
        private String password;
    
        @Test
        void contextLoads() {
            System.out.println(password);
            // 输出:5349
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

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

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

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

    如 0b_0101_0101 和 0x3f3f3f3f

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

  • 相关阅读:
    Real-ESRGAN—图像/视频修复算法
    字符串截取
    又一恶意软件:1000多名受害者均在韩国,不排除其他地区被攻击的可能
    2022牛客多校第四场C.Easy Counting Problem
    进度条小程序
    TMS320F280049学习5:CPU timer中断
    如何设计性能优良的mysql索引?
    vscode初次远程连接服务器报错解决
    nginx实战-frp+docker+nginx+tomcat内网穿透无法获取客户端真实ip
    合肥先进光源束测专用网络的规划-续
  • 原文地址:https://blog.csdn.net/Cey_Tao/article/details/127584000