信息发布→ 登录 注册 退出

Springboot @Value注入boolean设置默认值方式

发布时间:2026-01-11

点击量:
目录
  • @Value注入boolean设置默认值
    • 问题描述
    • 问题分析
    • 解决方案
    • @Value 源码阅读
  • Spring解析@Value

    @Value注入boolean设置默认值

    问题描述

    Springboot 中读取配置文件

    test:

    业务代码如下

    @Value("${test:true}")
    private boolean test;

    报错如下

    nested exception is org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'boolean'; nested exception is java.lang.IllegalArgumentException: Invalid boolean value []

    问题分析

    根据报错可知,主要问题在于 注入时 test 的值是 String 类型,无法转换成 boolean 类型。

    @Value("${test:true}")
    private String test;

    于是更改了接收类型,看看获取到的值是否是 true,结果发现 test 值为 “”,而不是设置的默认值

    解决方案

    报错问题在于只要配置文件中有 test: 所以系统就默认 test 为 “” 而不是按照我所设想的为空所以默认值为 true。

    直接删除配置文件中的 test: 即可正常启动。

    @Value 源码阅读

    在排查问题的过程中也粗略的跟读了一下源码

    //org.springframework.beans.TypeConverterSupport#doConvert()
    private <T> T doConvert(Object value, Class<T> requiredType, MethodParameter methodParam, Field field) throws TypeMismatchException {
         try {
             return field != null ? this.typeConverterDelegate.convertIfNecessary(value, requiredType, field) : this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
         } catch (ConverterNotFoundException var6) {
             throw new ConversionNotSupportedException(value, requiredType, var6);
         } catch (ConversionException var7) {
             throw new TypeMismatchException(value, requiredType, var7);
         } catch (IllegalStateException var8) {
             throw new ConversionNotSupportedException(value, requiredType, var8);
         } catch (IllegalArgumentException var9) {
         // 最终异常从这里抛出
             throw new TypeMismatchException(value, requiredType, var9);
         }
     }

    最终赋值在

    //org.springframework.beans.TypeConverterDelegate#doConvertTextValue()
    private Object doConvertTextValue(Object oldValue, String newTextValue, PropertyEditor editor) {
        try {
            editor.setValue(oldValue);
        } catch (Exception var5) {
            if (logger.isDebugEnabled()) {
                logger.debug("PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call", var5);
            }
        }
        // 此处发现 newTextValue 为 ""
        editor.setAsText(newTextValue);
        return editor.getValue();
    }

    接下来就是如何将 字符串 true 转换为 boolean 的具体代码:

    // org.springframework.beans.propertyeditors.CustomBooleanEditor#setAsText()
        public void setAsText(String text) throws IllegalArgumentException {
            String input = text != null ? text.trim() : null;
            if (this.allowEmpty && !StringUtils.hasLength(input)) {
                this.setValue((Object)null);
            } else if (this.trueString != null && this.trueString.equalsIgnoreCase(input)) {
                this.setValue(Boolean.TRUE);
            } else if (this.falseString != null && this.falseString.equalsIgnoreCase(input)) {
                this.setValue(Boolean.FALSE);
            } else if (this.trueString != null || !"true".equalsIgnoreCase(input) && !"on".equalsIgnoreCase(input) && !"yes".equalsIgnoreCase(input) && !"1".equals(input)) {
                if (this.falseString != null || !"false".equalsIgnoreCase(input) && !"off".equalsIgnoreCase(input) && !"no".equalsIgnoreCase(input) && !"0".equals(input)) {
                    throw new IllegalArgumentException("Invalid boolean value [" + text + "]");
                }
                this.setValue(Boolean.FALSE);
            } else {
                this.setValue(Boolean.TRUE);
            }
        }

    tips:windows 中使用 IDEA 去查找类可以使用 ctrl + shift +alt +N的快捷键组合去查询,mac 系统则是 commond + O

    Spring解析@Value

    1、初始化PropertyPlaceholderHelper对象

        protected String placeholderPrefix = "${";
     
        protected String placeholderSuffix = "}";
        @Nullable
        protected String valueSeparator = ":"; 
    private static final Map<String, String> wellKnownSimplePrefixes = new HashMap<>(4);
     
        static {
            wellKnownSimplePrefixes.put("}", "{");
            wellKnownSimplePrefixes.put("]", "[");
            wellKnownSimplePrefixes.put(")", "(");
        }
     
    public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix,
                @Nullable String valueSeparator, boolean ignoreUnresolvablePlaceholders) {
     
            Assert.notNull(placeholderPrefix, "'placeholderPrefix' must not be null");
            Assert.notNull(placeholderSuffix, "'placeholderSuffix' must not be null");
            //默认值${
            this.placeholderPrefix = placeholderPrefix;
            //默认值}
            this.placeholderSuffix = placeholderSuffix;
            String simplePrefixForSuffix = wellKnownSimplePrefixes.get(this.placeholderSuffix);
            //当前缀为空或跟定义的不匹配,取传入的前缀
            if (simplePrefixForSuffix != null && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) {
                this.simplePrefix = simplePrefixForSuffix;
            }
            else {
                this.simplePrefix = this.placeholderPrefix;
            }
            //默认值:
            this.valueSeparator = valueSeparator;
            this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
        }

    2、解析@Value 

    protected String parseStringValue(
                String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
     
            StringBuilder result = new StringBuilder(value);
            //是否包含前缀,返回第一个前缀的开始index
            int startIndex = value.indexOf(this.placeholderPrefix);
            while (startIndex != -1) {
                //找到最后一个后缀的index
                int endIndex = findPlaceholderEndIndex(result, startIndex);
                if (endIndex != -1) {
                    //去掉前缀后缀,取出里面的字符串
                    String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
                    String originalPlaceholder = placeholder;
                    if (!visitedPlaceholders.add(originalPlaceholder)) {
                        throw new IllegalArgumentException(
                                "Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
                    }
                    // 递归判断是否存在占位符,可以这样写${acm.endpoint:${address.server.domain:}}
                    placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
                    // 根据key获取对应的值
                    String propVal = placeholderResolver.resolvePlaceholder(placeholder);
                    // 值不存在,但存在默认值的分隔符
                    if (propVal == null && this.valueSeparator != null) {
                        // 获取默认值的索引
                        int separatorIndex = placeholder.indexOf(this.valueSeparator);
                        if (separatorIndex != -1) {
                            // 切掉默认值的字符串
                            String actualPlaceholder = placeholder.substring(0, separatorIndex);
                            // 切出默认值
                            String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
                            // 根据新的key获取对应的值
                            propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
                            // 如果值不存在,则把默认值赋值给当前值
                            if (propVal == null) {
                                propVal = defaultValue;
                            }
                        }
                    }
                    // 如果当前值不为NULL
                    if (propVal != null) {
                        // 递归获取存在占位符的值信息
                        propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
                        // 替换占位符
                        result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
                        if (logger.isTraceEnabled()) {
                            logger.trace("Resolved placeholder '" + placeholder + "'");
                        }
                        startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
                    }
                    else if (this.ignoreUnresolvablePlaceholders) {
                        // Proceed with unprocessed value.
                        startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
                    }
                    else {
                        throw new IllegalArgumentException("Could not resolve placeholder '" +
                                placeholder + "'" + " in value \"" + value + "\"");
                    }
                    visitedPlaceholders.remove(originalPlaceholder);
                }
                else {
                    startIndex = -1;
                }
            } 
            return result.toString();
        }

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

    在线客服
    服务热线

    服务热线

    4008888355

    微信咨询
    二维码
    返回顶部
    ×二维码

    截屏,微信识别二维码

    打开微信

    微信号已复制,请打开微信添加咨询详情!