SpringBoot属性绑定内部原理(ok)

1 配置文件位置

springboot 启动会扫描以下位置的 application.properties 或者 application.yml 文件作为 Spring boot 的默认配置文件

–file:./config/ 
–file:./ 项目的跟路径,如果当前的项目有父工程,配置文件要放在父工程 的根路径 
–classpath:/config/ 
–classpath:/ 

优先级由高到底,高优先级的配置会覆盖低优先级的配置;
SpringBoot 会从这四个位置全部加载主配置文件;互补配置;

2 指定配置文件名称

通过命令行参数 --spring.config.name 进行指定1~n个配置文件

# 指定一个
$ java -jar myproject.jar --spring.config.name=myproject 
## 指定多个
$ java -jar myproject.jar 
--spring.config.location=classpath:/default.properties,classpath:/override.prop
erties 

松散绑定

属性文件中配置 说明

acme.my-project.person.first-name 羊肉串模式 case, 推荐使用

acme.myProject.person.firstName 标准驼峰模式

acme.my_project.person.first_name 下划线模式

ACME_MYPROJECT_PERSON_FIRSTNAME 大写下划线,如果使用系统环境时候推荐使用

⭐️ 在java文件中的前缀是否可以使用驼峰模式与版本有关,SpringBoot1.5.9 可以,2.2.2不行

绑定属性内部原理

setName:32, User (com.yh.stu.springboot.property.bean)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
setValue:358, BeanWrapperImpl$BeanPropertyHandler (o.s.beans)
processLocalProperty:467, AbstractNestablePropertyAccessor (o.s.beans)
setPropertyValue:290, AbstractNestablePropertyAccessor (o.s.beans)
setPropertyValue:278, AbstractNestablePropertyAccessor (o.s.beans)
setPropertyValue:699, RelaxedDataBinder$RelaxedBeanWrapper (o.s.boot.bind)
setPropertyValues:95, AbstractPropertyAccessor (o.s.beans)
applyPropertyValues:859, DataBinder (o.s.validation)
doBind:755, DataBinder (o.s.validation)
doBind:128, RelaxedDataBinder (o.s.boot.bind)
bind:740, DataBinder (o.s.validation)
doBindPropertiesToTarget:272, PropertiesConfigurationFactory (o.s.boot.bind)
bindPropertiesToTarget:240, PropertiesConfigurationFactory (o.s.boot.bind)
postProcessBeforeInitialization:330, ConfigurationPropertiesBindingPostProcessor 
(o.s.b.context.properties)
postProcessBeforeInitialization:292, ConfigurationPropertiesBindingPostProcessor 
(o.s.b.context.properties)
applyBeanPostProcessorsBeforeInitialization:409, AbstractAutowireCapableBeanFactory 
(o.s.beans.factory.support)
initializeBean:1620, AbstractAutowireCapableBeanFactory (o.s.beans.factory.support)
doCreateBean:555, AbstractAutowireCapableBeanFactory (o.s.beans.factory.support)
createBean:483, AbstractAutowireCapableBeanFactory (o.s.beans.factory.support)
getObject:306, AbstractBeanFactory$1 (o.s.beans.factory.support)
getSingleton:230, DefaultSingletonBeanRegistry (o.s.beans.factory.support)
doGetBean:302, AbstractBeanFactory (o.s.beans.factory.support)
getBean:197, AbstractBeanFactory (o.s.beans.factory.support)
preInstantiateSingletons:761, DefaultListableBeanFactory (o.s.beans.factory.support)
finishBeanFactoryInitialization:867, AbstractApplicationContext (o.s.context.support)
refresh:543, AbstractApplicationContext (o.s.context.support)
refresh:122, EmbeddedWebApplicationContext (o.s.boot.context.embedded)
refresh:693, SpringApplication (o.s.boot)
refreshContext:360, SpringApplication (o.s.boot)
run:303, SpringApplication (o.s.boot)
main:28, PropertyTestMainSpringApplication (com.yh.stu.springboot.property)
getBeanPostProcessors() = {ArrayList@5072}  size = 12
 0 = {ApplicationContextAwareProcessor@5137} 
 1 = {WebApplicationContextServletContextAwareProcessor@5138} 
 2 = {ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor@5139} 
 3 = {PostProcessorRegistrationDelegate$BeanPostProcessorChecker@5140} 
 4 = {ConfigurationPropertiesBindingPostProcessor@4387} 
 5 = {MethodValidationPostProcessor@5141} 
 6 = {EmbeddedServletContainerCustomizerBeanPostProcessor@5142} 
 7 = {ErrorPageRegistrarBeanPostProcessor@5143} 
 8 = {CommonAnnotationBeanPostProcessor@5144} 
 9 = {AutowiredAnnotationBeanPostProcessor@5145} 
 10 = {RequiredAnnotationBeanPostProcessor@5146} 
 11 = {ApplicationListenerDetector@5147} 

IDE中yml/properties文件无提示问题

需要加入如下的依赖

<!-- 为了让当前的实体类能在配置文件中有对应的提示-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

加入这个依赖后, 使用依赖提供的API在编译项目的时候处理@ConfigurationProperties注释的类, 生成您自己的配置元数据文件, 大家可以在你的项目中找到 ..\classes\META-INF\spring-configuration-metadata.json 文件 ,这个文件就是生成的元数据文件, IDE 基于这个文件给你提示了!!

注意:
有时候在idea中的加入了上面的依赖,但application.yml或者properties文件还是不提示, 这个时候文件的图标通常不是spring的绿色,此时应该在idea中设置 : shift + ctrl + alt + s
在这里插入图片描述在输入框中输入你的文件名,然后确定就ok了 !

ConfigurationPropertiesBindingPostProcessor 进行属性绑定

测试程序

@SpringBootApplication
@EnableConfigurationProperties(User.class)
public class PropertyTestMainSpringApplication {
    public static void main(String[] args) throws InterruptedException {
        SpringApplication springApplication
                = new SpringApplication(PropertyTestMainSpringApplication.class);
        springApplication.setDefaultProperties(getDefaultProperties());
        springApplication.run(args);
    }
}

@ConfigurationProperties("dept.user")
public class User {
    private long id;
    private String name;
    private Date birthday;
    private List<String> toyNames;
    private Set<String> socks;
    // get/set 略....
}

application.yml 文件

server:
  port: 7789
dept:
  user:
    name: name7789

User 类上没有标注@Component之类的注解,且@ConfigurationProperties也不是@Component派生的注解, Spring能将User对象纳入容器管理么?

从注解@EnableConfigurationProperties(User.class) 来看 ,好像Spring容器应该将其纳入其中进行管理了, 这里面的过程是什么样的?

带着疑问我们在User 的setName方法上打上断点 ,然后查看调用栈 , 看看这个过程到底是什么样的?

setName:37, User (com.yh.stu.springboot.property.bean)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
setValue:358, BeanWrapperImpl$BeanPropertyHandler (o.s.beans)
processLocalProperty:467, AbstractNestablePropertyAccessor (o.s.beans)
setPropertyValue:290, AbstractNestablePropertyAccessor (o.s.beans)
setPropertyValue:278, AbstractNestablePropertyAccessor (o.s.beans)
setPropertyValue:699, RelaxedDataBinder$RelaxedBeanWrapper (o.s.boot.bind)
setPropertyValues:95, AbstractPropertyAccessor (o.s.beans)
applyPropertyValues:859, DataBinder (o.s.validation)
doBind:755, DataBinder (o.s.validation)
doBind:128, RelaxedDataBinder (o.s.boot.bind)
bind:740, DataBinder (o.s.validation)
doBindPropertiesToTarget:272, PropertiesConfigurationFactory (o.s.boot.bind)
bindPropertiesToTarget:240, PropertiesConfigurationFactory (o.s.boot.bind)
postProcessBeforeInitialization:330, ConfigurationPropertiesBindingPostProcessor 
(o.s.boot.context.properties)
// 这里调用了BeanPostProcessor类型的实例
// ConfigurationPropertiesBindingPostProcessor的postProcessBeforeInitialization方法
postProcessBeforeInitialization:292, ConfigurationPropertiesBindingPostProcessor
(o.s.boot.context.properties)
// 初始化规则之一在调用初始化方法前从容器中拿到所有的 BeanPostProcessor,调用其postProcessBeforeInitialization
applyBeanPostProcessorsBeforeInitialization:409, AbstractAutowireCapableBeanFactory
(o.s.beans.factory.support)
// 即在创建好bean后,会对bean进行一些初始化的工作
initializeBean:1620, AbstractAutowireCapableBeanFactory (o.s.beans.factory.support)
doCreateBean:555, AbstractAutowireCapableBeanFactory (o.s.beans.factory.support)
createBean:483, AbstractAutowireCapableBeanFactory (o.s.beans.factory.support)
getObject:306, AbstractBeanFactory$1 (o.s.beans.factory.support)
getSingleton:230, DefaultSingletonBeanRegistry (o.s.beans.factory.support)
doGetBean:302, AbstractBeanFactory (o.s.beans.factory.support)
// beanName是这样的:dept.user-com.yh.stu.springboot.property.bean.User
// 和普通beanName还是有区别的 ,这里就好奇这个beanName是如何生成并注册进来的 
// 我们后续可以在注册BeanDefinition的地方打上断点看看
getBean:197, AbstractBeanFactory (o.s.beans.factory.support)
preInstantiateSingletons:761, DefaultListableBeanFactory (o.s.beans.factory.support)
finishBeanFactoryInitialization:867, AbstractApplicationContext (o.s.context.support)
// 容器实例化 bean阶段
refresh:543, AbstractApplicationContext (o.s.context.support)
refresh:122, EmbeddedWebApplicationContext (o.s.boot.context.embedded)
refresh:693, SpringApplication (o.s.boot)
refreshContext:360, SpringApplication (o.s.boot)
run:303, SpringApplication (o.s.boot)
main:31, PropertyTestMainSpringApplication (com.yh.stu.springboot.property)

@EnableConfigurationProperties 原理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java硕哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值