自信满满分享ioc,结果暴躁debug结束.
点一根🚬,分享一下我踩的坑.
前情是,xml配置下想当然的以为application.properties配置或application.yml配置都存储在环境组件中.结果就是,无论什么方式都从environment中拿不到配置,但是@Value注解能正确解析.
但是, 为什么通过@PropertySource("classpath:application.properties"),就能从environment拿到? 掀开它的头盖骨看看.
1.传统xml配置
在传统SpringFramework的容器,如ClassPathXmlApplicationContext中,不会自动加载application.yml或application.properties文件,也不会自动注册PropertySourcesPlaceholderConfigurer占位符解析器.如果要加载配置文件,在xml文件中做如下配置:
<context:property-placeholder location="classpath:application.properties"/>
在解析xml文件时,Spring会构建PropertySourcesPlaceholderConfigurer.class类型BeanDefinition,并注册到beanFactory.
同时,根据类的继承关系可知,PropertySourcesPlaceholderConfigurer是一个BFPP.而BFPP的主要功能就是在bean实例化之前,对BeanDefinition新增/修改.
在容器启动的refresh()方法中,会调用invokeBeanFactoryPostProcessors(beanFactory),此方法会执行BFPP的postProcessBeanFactory()方法,从源码中可以看到,针对properrySources字段中分别添加了环境组件 ConfigurableEnvironmentPropertySource和PropertiesPropertySource.
在构建PropertiesPropertySource时,会根据location地址加载用户配置,单独存储在localProperties键值对中.
因此可以知道,用户配置并不在environment中,而是单独存储.
同时PropertySourcesPlaceholderConfigurer还向容器中注册了内置的值处理器.
这个StringValueResolver可以被后续的AutowireAnnotationBeanPostProcessor调用,用来解析@Value("${...}")的字符串,将解析到的值注入字段/方法参数.
2.通过注解方式
当通过注解的方式配置application.properties/application.yml,那么配置加载方式就不一样了.
@PropertySource注解功能就是用来配置外部属性资源.使用这个注解就必须搭配@Component注解或衍生注解(比如@Service@Configuration)一起使用.
它的加载流程是:
1,包扫描将标注了@Component以及衍生注解的类加载到容器构建BeanDefinition.
2,通过一个特殊的BFPP,也就是ConfigurationClassPostProcessor解析配置类(类上有以下注解或者@Configuration注解或者类中@Bean注解)
3,通过doProcessConfigurationClass方法解析PropertySource,将配置文件中的属性值注入到environment中.
ConfigurationClassPostProcessor特殊在实现了BeanDefintionRegistryPostProcessor.
在BeanDefintionRegistryPostProcessor中有一个非常重要的方法postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry),这个方法允许,在BeanDefinition加载完成之后及Bean实例化之前,直接操作BeanDefinitionRegistry,动态注册新的BeanDefinition.
深入debug在doProcessConfigurationClass方法中,查找类上是否有@PropertySource注解.
从图上可以看到,在MyTest类上,解析到@PropertySource的属性值.不断深入debug可以看到通过location地址加载文件,最终用户配置信息存入environment中
代码走到这里,可以看到通过注解加载的配置是放入environment中的.
后续@Value注解的解析是通过EmbeddedValueResolver,而EmbeddedValueResolver会通过Environment获取PropertyResolver来解析占位符. 就不在需要PropertySourcesPlaceholderConfigurer.
最后总结,如果在beans标签的XML定义中使用占位符,或者在一些非@Value的地方(如property标签),需要使用PropertySourcesPlaceholderConfigurer,此时配置信息并不存储在environment中.而通过@PropertySource加载的配置信息,是存储在environment中这是从配置加载到数据存储都不同的两套系统.
另,@Value的解析,下次分享.