好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

@Value注入boolean设置默认值

问题描述

Springboot 中读取配置文件

?

1

test:

业务代码如下

?

1

2

@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 类型。

?

1

2

@Value ( "${test:true}" )

private String test;

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

解决方案

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

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

@Value 源码阅读

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

//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);

      }

  }

最终赋值在

?

1

2

3

4

5

6

7

8

9

10

11

12

13

//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 的具体代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

// 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对象

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

    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 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

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();

     }

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

原文链接:https://blog.csdn.net/mochi_li/article/details/106349403

查看更多关于Springboot @Value注入boolean设置默认值方式的详细内容...

  阅读:17次