• Spring注解之@Value注解读取配置文件属性


    概述

      在Spring 组件中,通常使用@Value注解读取 properties 文件的配置值。但如果在配置文件或启动参数中未指定对应的参数值,则项目在启动的时候会抛出异常,导致服务启动失败,异常信息往往提示缺少必要的属性配置信息:

    Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'self.user.address' in value "${self.user.address}"
    	at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180) ~[spring-core-5.3.7.jar:5.3.7]
    	at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126) ~[spring-core-5.3.7.jar:5.3.7]
    	at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:239) ~[spring-core-5.3.7.jar:5.3.7]
    	at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210) ~[spring-core-5.3.7.jar:5.3.7]
    	at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:175) ~[spring-context-5.3.7.jar:5.3.7]
    	at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:936) ~[spring-beans-5.3.7.jar:5.3.7]
    	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1321) ~[spring-beans-5.3.7.jar:5.3.7]
    	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) ~[spring-beans-5.3.7.jar:5.3.7]
    	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:657) ~[spring-beans-5.3.7.jar:5.3.7]
    	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.3.7.jar:5.3.7]
    	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.7.jar:5.3.7]
    	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.7.jar:5.3.7]
    	... 17 common frames omitted
    

      解决办法是在Apollo等配置文件中对@Value对应的值进行配置,或设置默认值。本文介绍@Value注解的语法糖,介绍如何设置key的默认值,介绍如何配置数组、列表和map的初始值。

    @Value注解语法糖

      注解@Value用于读取配置文件中的属性,语法糖有以下三种。

    (1) 直接赋值

    @Value("string value")

      这种方式就是直接把要注入的值字面量写在注解里,比较少用。如果要写死在注解里了,那直接定义变量的时候写死就可以了。

    (2) 使用占位符$

    @Value(${key : default_value})

      这是最常用的姿势,通过属性名的key,将值注入变量。default_value为默认值。$注入的是配置文件对应的property,使用“:”对未配置或值为空的key设置默认值。

    (3)SpEL表达式

    @Value(#{self.key?: default_value})

      使用 Spring Expression Language (SpEL) 设置默认值。#注入的是SpEL表达式对应的内容,使用“?:”对未配置或值为空的表达式设置默认值。

      另外,占位符和SpEL表达式可以双剑合璧,解锁方式如下:

    @Value("#{'${listOfValues}'.split(',')}")
    private List valueList;

      温馨提示,内外顺序不能颠倒,必须是#{}外面,${}在里面!

    使用场景

      对于注入的场景,主要有三种:

    (1)bean声明的变量,香饽饽级别用法。

    (2)setter方法注入,不常用。

    (3)构造方法或其它方法的入参,这就是鸡肋,不能把关键参数写死。

      示例如下:

    //bean声明的变量
    public static class MyValues {
        @Value("${self.user.name}")
        private String userName;
    }
    
    //setter 方法中
    public static class MyValues {
        private String userName;
        @Value("${self.user.name}")
        public void setUserName(String userName) {
            this.userName = userName;
        }
    }
    
    //方法入参
    public class MyValues {
        private String userName;
        @Autowired
        public void configure(@Value("${self.user.name}") String userName) {
            this.userName = userName;
        }
    }
    

    基本类型

      设置默认值时,在key后加上冒号及其默认值即可,方法如下:

    public class ReadConfig {
        // 未指定默认值
        @Value("${self.user.name}")
        private String userName;
        // 使用英文冒号指定默认值为“defaultValue”
        @Value("${self.user.address:defaultValue}")
        private String userAddress;
        
        @Value("${self.bool:true}")
        private boolean booleanWithDefaultValue;
        
        @Value("${self.user.age:21}")
        private Integer userAge;
    }
    

      针对以上第一种@Value注解的使用方式,如果username对应的属性值未在Apollo、application.properties文件中配置或未在java -jar命令中传递参数,那么服务启动时将抛出 IllegalArgumentException 异常,导致服务发布失败。而关于第二种方式,通过“:”指定默认值,则可以正常启动服务。

    数组和列表

      在配置文件中配置数组或者列表时,使用的默认分隔符是英文逗号,也可以自定义。 demo如下:

    self.array = xxx1,xxx2,xxx3

      基于配置文件注入属性值:

    /**
     * 注入数组,默认','分隔
     */
    @Value("${self.array:one,two,three}")  
    String[] array;
    
    /**
     * 注入列表,分隔符使用英文分号
     */
    @Value("#{'${self.empty.array:}'.empty ? null : '${self.empty.array}'.split(';')}")
    List<String> list;
    

    设置map

    @Value("#{${self.map1:{name: 'default', age: 18, city: '河南'}}}")
    private Map<String, Object> defaultMap;

      map设置默认值也是使用英文冒号。

    综合实战

      配置文件配置如下:

    self.param.user.name = 楼兰胡杨
    self.array = xxx1,xxx2,xxx3
    self.map={name: 'Wiener', age: '18', city: '商丘'}
    

      测试用例如下:

    // 指定默认值
        @Value("${self.user.name:defaultValue}")
        private String userName;
    
        @Value("${self.array}")
        private List<String> myList;
        @Value("${self.array:one,two,three}")
        private String[] myArray;
        // 未配置属性,使用默认值空数组
        @Value("${self.empty.array:}")
        private String[] myEmptyArray;
        // 未配置属性,使用null
        @Value("#{'${self.empty.array:}'.empty ? null : '${self.empty.array}'.split(',')}")
        private List<String> myNullList;
        @Value("#{${self.map}}")
        private Map<String, Object> myMap;
        @Value("#{${self.map}.city}")
        private String cityValue;
    
        @Value("#{${self.map1:{name: 'default', age: 18, city: '河南'}}}")
        private Map<String, Object> defaultMap;
        //表达式结果
        @Value("#{ T(java.lang.Math).random() * 100.0 }")
        private double randomNumber;
        
        @PostMapping("/readConfig")
        public Map<String, Object> readConfig(@Value("${self.param.user.name}") String myUserName) {
            System.out.println("鸡肋般的传参 myUserName=" + myUserName);
            System.out.println("#````````````````````````# userName=" + userName);
            System.out.println("#````````````````````````# myList=" + myList);
            System.out.println("#````````````````````````# cityValue=" + cityValue);
            System.out.println("#``````使用默认值 defaultMap=" + defaultMap);
            System.out.println("#````````````````````````# myArray=");
            for (String one : myArray) {
                System.out.println(one + " 数组");
            }
            System.out.println("空数组myEmptyArray大小:" + myEmptyArray.length);
            System.out.println("空列表myNullList是否为null:" + CollectionUtils.isEmpty(myNullList));
            System.out.println("random number:" + randomNumber);
            return myMap;
        }
    

      执行结果如下:

    鸡肋般的传参 myUserName=楼兰胡杨
    #````````````````````````# userName=defaultValue
    #````````````````````````# myList=[xxx1, xxx2, xxx3]
    #````````````````````````# cityValue=商丘
    #``````使用默认值 defaultMap={name=default, age=18, city=河南}
    #````````````````````````# myArray=
    xxx1 数组
    xxx2 数组
    xxx3 数组
    空数组myEmptyArray大小:0
    空列表myNullList是否为null:true
    random number:41.28241165389434
    

    小结

      本文结合案例讲解了@Value注解的使用方法,包括如何设置数组、列表和map的默认值。

      最后,奉上一个归纳总结,如下图[1]所示:


    Spring @Value 注解

      对于Wiener以上的话题,大家又有什么自己的独特见解呢?欢迎在下方评论区留言!

    Reference

    [1] https://segmentfault.com/a/1190000021415142?utm_source=tag-newest
  • 相关阅读:
    如何在linux服务器下快速安装配置Node.js
    光纤路由器曝远程命令执行漏洞 上百万台家用路由器易遭劫持
    光纤路由器曝远程命令执行漏洞 上百万台家用路由器易遭劫持
    编写高性能JavaScript
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/east7/p/15876526.html
Copyright © 2020-2023  润新知