讲到这里,refresh()中核心方法就剩下finishBeanBactoryInitialization()方法没讲,这个方法主要是Bean的实例化、依赖注入、AOP,在讲这个方法之前我们讲一些其他的知道,如属性文件解析、如果没有配置文件,那么BeanDefinition怎么来的,Bean的实例化是依赖于BeanDefinition,今天就讲一讲属性文件的解析。

1.进入ContextNamespaceHandler类

我们知道context标签的handler是ContextNamespaceHandler,在是这个类的init()方法完成对各个具体标签的注册,property-placeholder属性文件解析对应的处理类是PropertyPlaceholderBeanDefinitionParser.。

12.spring源码之属性文件解析_属性文件

2.进入PropertyPlaceholderBeanDefinitionParser类

具体的解析其实交给PropertySourcePlaceholderConfigurer这个类来完成的,这个类是一个BeanFactoryPostProcessor接口的一个实现,在前面讲过,对实现了BeanFactoryPostProcessor接口的类会调用它的postProcessorBeanFactory()方法,而属性文件的解析就是在这个方法中完成的

12.spring源码之属性文件解析_属性文件_02

3.PropertySourcePlaceholderConfigurer类的postProcessorBeanFactory()方法

这个方法就是把Environment和属性文件中key、value放入Properties对象,然后把Properties对象封装成PropertySource对象,然后加入到MutablePropertySource的list容器中

12.spring源码之属性文件解析_封装_03

12.spring源码之属性文件解析_封装_04

 

把属性文件中key、value放入Properties对象在mergeProperties()方法中

12.spring源码之属性文件解析_依赖注入_05

 

12.spring源码之属性文件解析_封装_06

4.进入processProperties()方法

12.spring源码之属性文件解析_实例化_07

5.进入doprocessProperties()方法

12.spring源码之属性文件解析_属性文件_08

12.spring源码之属性文件解析_依赖注入_09

6.进入visitBeanDefinition()方法

除了属性值可以配置在属性配置文件中,类、工厂方法名等都可以。以PropertyValue为例

12.spring源码之属性文件解析_属性文件_10

7.进入visitPropertyValues()方法

12.spring源码之属性文件解析_解析器_11

8.进入resolveValue()方法

12.spring源码之属性文件解析_依赖注入_12

9.进入rsolverStringValue()方法

12.spring源码之属性文件解析_属性文件_13

 

12.spring源码之属性文件解析_实例化_14

10.进入replacePlaceholder()方法

12.spring源码之属性文件解析_实例化_15

11.进入parseStringValue()方法,真正的解析是在这个方法完成的

12.spring源码之属性文件解析_封装_16

resolverPlaceholder()方法其实就是从Properties对象中根据key拿到value值,placeholder就是${}的key值

12.spring源码之属性文件解析_依赖注入_17

最终都是通过getProperty()方法根据Key从Properties中获取value值。像Environment,在最开始的postProcessorBeanFactory()方法中处理Environment的时候就重写了getProperty()方法,就是从environment根据Key获取value值

12.spring源码之属性文件解析_依赖注入_18

12.回到第4步中,我们看一下@Value注解的解析
12.spring源码之属性文件解析_属性文件_19

StringValueResolver这个接口中只有一个resolveStringValue()方法,调用这个方法就会走这个lambda表达式的代码,在第5步的时候把解析器放入了一个容器中,在依赖注入解析@Value的时候就会从容器中拿到这个解析器,调用resolveStringValue()方法,然后就会执行这个lambda表达式的内容,完成@value的解析,从属性文件中获取value值,完成依赖注入。

12.spring源码之属性文件解析_实例化_20

12.spring源码之属性文件解析_解析器_21

其实也是一样调用getProperty()方法

12.spring源码之属性文件解析_依赖注入_22

再看replacePlaceholders()方法,最终也会走到parseStringValue这个方法

12.spring源码之属性文件解析_解析器_23

13.应用

从源码来看,变量值的获取无非就是从environemt对象或者属性文件中封装成的PropertySource中获取,那么如果我们属性文件没有配置这变量,又想要获取值,怎么办?我们可以手动往environment中添加,从3中可以看到,无非就是把key、value封装成一个Properties,然后封装成PropertySource对象,然后加入到MutablePropertySource的list容器中,

1.属性文件中:

12.spring源码之属性文件解析_属性文件_24

 

2.创建一个类实现EnvironmentAware接口

12.spring源码之属性文件解析_实例化_25

这里会调用setEnvironment()方法,知道就行,会面会讲,实现了EnvironmentAware接口,就会调用setEnvironment()方法。

3.测试

12.spring源码之属性文件解析_解析器_26

4.往environment对象中添加属性

12.spring源码之属性文件解析_封装_27

5.再测试

12.spring源码之属性文件解析_属性文件_28

其实通过源码,根据源码的流程就可以写出很多自己的应用。