SpringBoot2.x升级踩坑,一个下划线引起的血案

最近公司项目在作SpringBoot的升级,在升级过程当中遇到了一些问题,简单记录一下,作个分享。另外,本文中的程序只为示例代码,并不是公司生产环境代码。java

遇到什么问题

从SpringBoot1.x升级到SpringBoot2.x以后,解决完编译异常,运行程序,在程序启动时报错:spring

报错信息

报错信息就已经很直白的告诉了咱们错误缘由:springboot

配置属性名称“com_shen”无效app

无效字符: '_', 缘由:规范名称应为kebab-case(用'-'分隔),小写字母数字字符,而且必须以字母开头ide

怎么解决

通过排查,是由于在application.properties文件中有以下一个配置项:spring-boot

com_shen.name=xiaohei
复制代码

对应Java程序代码:post

@Getter
@Setter
@ConfigurationProperties(prefix = "com_shen")
public class Service {
    private String name;
}

复制代码

结合报错日志,咱们能够很容易的解决这个问题,去掉配置项中的_,将配置项name修改成com.shen.name便可。spa

源码解析

你觉得文章写到这里就结束了吗?其实并无。hhhhhh,经过这个问题,咱们来看一下SpringBoot2.x的内部源码。什么,你不知道该从哪里入手来看这个源码,不要紧,咱们一步一步来。翻译

点开@ConfigurationProperties源码,debug

@ConfigurationProperties源码

在Spring中,大量的功能都是经过BeanPostProcessor来实现的。并且,Spring中的源码注释写的很是的仔细。经过源码注释咱们能够猜到多是ConfigurationPropertiesBindingPostProcessor这个类在负责@ConfigurationProperties注解的背后支持。

点开ConfigurationPropertiesBindingPostProcessor类源码,发如今该类中Override了BeanPostProcessorpostProcessBeforeInitialization方法:

ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization
在这个方法中,调用了 bind(bean, beanName, annotation);方法。这个方法名叫"绑定",方法中传入了bean、beanName和annotation的信息,经验告诉我这个方法大几率就是在负责解析 @ConfigurationProperties,进行属性绑定。

因而,在这里打一个条件断点,debug运行项目:

条件断点

经过debug发现的确是这个方法在进行属性绑定。并且底层调用了org.springframework.boot.context.properties.bind.Binder#bind(String, Bindable<T>, BindHandler) 方法:

bind方法

在这个bind方法中,又调用了另外一个方法bind(ConfigurationPropertyName.of(name), target, handler);,并且经过name生成了ConfigurationPropertyName对象ConfigurationPropertyName.of(name),经过方法名咱们能够猜想,这个方法多是在负责解析Configuration Property Name,项目启动的报错信息颇有多是这个方法中抛出的。点开源码:

org.springframework.boot.context.properties.source.ConfigurationPropertyName#of

发如今这个方法中,调用了InvalidConfigurationPropertyNameException.throwIfHasInvalidChars(name,ElementValidator.getInvalidChars(elementValue));。Spring代码命名真的是太优雅了,虽然名称很长,可是让源码阅读者一看就能明白这个方法在作什么。

`InvalidConfigurationPropertyNameException.throwIfHasInvalidChars方法

ElementValidator.getInvalidChars(elementValue)方法

经过源码,咱们能够看到,在SpringBoot中对Configuration property name中的字符进行了有效性的判断,判断规则如上图所示。

ElementValidator类是ConfigurationPropertyName的一个内部类。ConfigurationPropertyName是SpringBoot2.0新增的一个类,让咱们一块儿来阅读一下类中注释,了解一下这个类:

ConfigurationPropertyName

机器翻译结果以下:

由点分隔的元素组成的配置属性名称。 用户建立的名称能够包含字符“ a-z”,“ 0-9”)和“-”,它们必须为小写字母,而且必须以字母数字字符开头。 “-”仅用于格式化,即“ foo-bar”和“ foobar”被认为是等效的。 “ [”和“]”字符可用于表示关联索引(即Map键或Collection索引。索引名称不受限制,而且区分大小写。

如下是一些典型示例:

spring.main.banner-mode server.hosts [0]。名称 日志[org.springboot] .level

使用@Value

咱们知道,SpringBoot中除了可使用@ConfigurationProperties以外,还可使用@Value

Demo程序以下:

@Getter
@Setter
@Component
public class Service {

    @Value("${com_shen.name}")
    private String name;
}
复制代码

application.properties文件:

com_shen.name=xiaohei
复制代码

在这种状况下,项目依旧启动成功了,并且成功的获取到了com_shen.name的属性值。也就是说,@Value注解中并无表达式作限制。

拓展阅读

Property Binding in Spring Boot 2.0 : spring.io/blog/2018/0…


欢迎关注公众号:

Coder小黑
相关文章
相关标签/搜索