
《Spring6核心技术》第11章:深度解析@Value注解
五、源码解析
5.2 为@Value修饰的属性赋值
本节主要对为@Value修饰的属性赋值的源码流程进行简单的分析,结合源码执行的时序图,会理解的更加深刻,本节的源码执行流程可以结合图11-3~11-4进行理解。具体分析步骤如下所示。
注意:为@Value修饰的属性赋值的源码流程的前半部分与本章5.1节分析源码的流程相同,这里,同样从AbstractAutowireCapableBeanFactory类的doCreateBean()方法开始分析。
(1)解析AbstractAutowireCapableBeanFactory类的doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)方法
源码详见:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)。重点关注如下代码片段。
可以看到,在AbstractAutowireCapableBeanFactory类的doCreateBean()方法中,会调用populateBean方法为Bean的属性赋值。
(2)解析AbstractAutowireCapableBeanFactory类的populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)方法
源码详见:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)。
可以看到,在populateBean()方法中,会调用InstantiationAwareBeanPostProcessor类的postProcessProperties()方法来处理属性或方法的值。实际上是调用的AutowiredAnnotationBeanPostProcessor类的postProcessProperties()方法。
(3)解析AutowiredAnnotationBeanPostProcessor类的postProcessProperties(PropertyValues pvs, Object bean, String beanName)方法
源码详见:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties(PropertyValues pvs, Object bean, String beanName)。
可以看到,在AutowiredAnnotationBeanPostProcessor类的postProcessProperties()方法中,会调用findAutowiringMetadata()方法获取注解的元数据信息。
(4)解析AutowiredAnnotationBeanPostProcessor类的findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs)方法
源码详见:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs)。
由于在之前解析并获取@Value修饰的属性的代码流程中,已经完成了对@Value 修饰的属性的获取工作。所以,程序执行到findAutowiringMetadata()方法内部时,injectionMetadataCache缓存中已经有数据了。
(5)返回AutowiredAnnotationBeanPostProcessor类的postProcessProperties(PropertyValues pvs, Object bean, String beanName)方法。在AutowiredAnnotationBeanPostProcessor类的postProcessProperties()方法中,调用了metadata对象的inject()方法为属性赋值。
(6)解析InjectionMetadata类的inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs)方法
源码详见:org.springframework.beans.factory.annotation.InjectionMetadata#inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs)。
可以看到,在InjectionMetadata类的inject()方法中,会循环遍历checkedElements集合,调用遍历出的每个InjectedElement对象的inject()方法为属性赋值。
注意:调用InjectedElement对象的inject()方法时,实际上可能会调用AutowiredFieldElement类的inject()方法、AutowiredMethodElement类的inject()方法或者InjectedElement类的inject()方法。这里,以调用AutowiredFieldElement类的inject()方法为例进行说明。
(7)解析AutowiredFieldElement类的inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)方法
源码详见:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)。
可以看到,在AutowiredFieldElement类的inject()方法中,会调用resolveFieldValue()方法来获取对应的属性值,如下所示。
并通过反射向使用@Value注解标注的字段赋值,如下所示。
(8)返回AbstractAutowireCapableBeanFactory类的doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)方法。再来看下源码:
可以看到,在AbstractAutowireCapableBeanFactory类的doCreateBean()方法中,为Bean的属性赋值后会调用initializeBean()方法对Bean进行初始化。
(9)解析AbstractAutowireCapableBeanFactory类的initializeBean(String beanName, Object bean, RootBeanDefinition mbd)方法
源码详见:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(String beanName, Object bean, RootBeanDefinition mbd)。
可以看到,在AbstractAutowireCapableBeanFactory类的initializeBean()方法中,会调用applyBeanPostProcessorsBeforeInitialization()方法在初始化之前执行一些逻辑,然后调用invokeInitMethods()执行真正的初始化操作,执行完Bean的初始化,会调用applyBeanPostProcessorsAfterInitialization()方法执行初始化之后的一些逻辑。
至此,为@Value修饰的属性赋值的源码流程分析完毕。
5.3 使用@Value获取属性的值
本节主要对使用@Value获取属性的值的源码流程进行简单的分析,结合源码执行的时序图,会理解的更加深刻,本节的源码执行流程可以结合图11-5~11-7进行理解。具体分析步骤如下所示。
注意:使用@Value获取属性的值的源码流程的前半部分与本章5.2节分析源码的流程相同,这里,从AutowiredFieldElement类的inject()方法开始分析。
(1)解析AutowiredFieldElement类的inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)方法
源码详见:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)。
可以看到,在AutowiredFieldElement类的inject()方法中,会调用resolveFieldValue()方法处理获取属性的值。
(2)解析AutowiredFieldElement类的resolveFieldValue(Field field, Object bean, @Nullable String beanName)方法
源码详见:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue(Field field, Object bean, @Nullable String beanName)。
可以看到,在AutowiredFieldElement类的resolveFieldValue()方法中,会调用beanFactory对象的resolveDependency()方法,继续向下分析。
(3)解析DefaultListableBeanFactory类的resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable SetautowiredBeanNames, @Nullable TypeConverter typeConverter)
源码详见:org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable SetautowiredBeanNames, @Nullable TypeConverter typeConverter)。
可以看到,在DefaultListableBeanFactory类的resolveDependency()方法中,会调用doResolveDependency()方法进一步处理。
(4)解析DefaultListableBeanFactory类的doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable SetautowiredBeanNames, @Nullable TypeConverter typeConverter)方法
源码详见:org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable SetautowiredBeanNames, @Nullable TypeConverter typeConverter)。
可以看到,在DefaultListableBeanFactory类的doResolveDependency()方法中,如果当前获取到的数据是String类型,则调用resolveEmbeddedValue()方法进行处理。
(5)解析AbstractBeanFactory类的resolveEmbeddedValue(@Nullable String value)方法
源码详见:org.springframework.beans.factory.support.AbstractBeanFactory#resolveEmbeddedValue(@Nullable String value)。
可以看到,在AbstractBeanFactory类的resolveEmbeddedValue()中,会调用遍历出来的StringValueResolver对象的resolveStringValue()方法进行处理。此时,会进入AbstractEnvironment类的resolvePlaceholders(String text)方法。
(6)解析AbstractEnvironment类的resolvePlaceholders(String text)方法
源码详见:org.springframework.core.env.AbstractEnvironment#resolvePlaceholders(String text)。
可以看到,在AbstractEnvironment类的resolvePlaceholders()方法中,会调用propertyResolver对象的resolvePlaceholders()方法进行处理。
(7)解析AbstractPropertyResolver类的resolvePlaceholders(String text)方法
源码详见:org.springframework.core.env.AbstractPropertyResolver#resolvePlaceholders(String text)。
可以看到,在AbstractPropertyResolver类的resolvePlaceholders()方法中,会调用doResolvePlaceholders()方法进一步处理。
(8)解析AbstractPropertyResolver类的doResolvePlaceholders(String text, PropertyPlaceholderHelper helper)方法
源码详见:org.springframework.core.env.AbstractPropertyResolver#doResolvePlaceholders(String text, PropertyPlaceholderHelper helper)。
可以看到,在AbstractPropertyResolver类的doResolvePlaceholders()方法中,会解析 ${xxx.xxx} 这种占位,最终获取到 key = xxx.xxx,随后根据key去资源文件(xml、application.properties、Environment 等)中查找是否配置了这个key的值。其实是通过调用helper的replacePlaceholders()方法并以Lambda表达式的方式传入getPropertyAsRawString()方法实现的。
(9)解析PropertyPlaceholderHelper类的replacePlaceholders(String value, PlaceholderResolver placeholderResolver)方法
源码详见:org.springframework.util.PropertyPlaceholderHelper#replacePlaceholders(String value, PlaceholderResolver placeholderResolver)。
可以看到,在PropertyPlaceholderHelper类的replacePlaceholders()方法中,会调用parseStringValue()方法解析String类型的数据。
(10)解析PropertyPlaceholderHelper类的parseStringValue(String value, PlaceholderResolver placeholderResolver, @Nullable SetvisitedPlaceholders)方法
源码详见:org.springframework.util.PropertyPlaceholderHelper#parseStringValue(String value, PlaceholderResolver placeholderResolver, @Nullable SetvisitedPlaceholders)。
在PropertyPlaceholderHelper类的parseStringValue()方法中重点关注如下代码片段。
会调用placeholderResolver对象的resolvePlaceholder()方法传入解析 ${xxx.xxx} 占位符,获取到的key,其中key的形式为xxx.xxx。调用placeholderResolver对象的resolvePlaceholder()方法会最终调用PropertySourcesPropertyResolver类的getPropertyAsRawString()方法。
(11)解析PropertySourcesPropertyResolver类的getPropertyAsRawString(String key)方法
源码详见:org.springframework.core.env.PropertySourcesPropertyResolver#getPropertyAsRawString(String key)。
可以看到,在getPropertyAsRawString()方法中,会调用getProperty()方法获取属性的值。在调用getPropertyAsRawString()方法时,传入的Key的形式的规则就是:如果使用@Value标注的属性为 ${xxx.xxx} 占位符,则此处传入的Key的形式为xxx.xxx。
(12)解析PropertySourcesPropertyResolver类的getProperty(String key, ClasstargetValueType, boolean resolveNestedPlaceholders)方法
源码详见:org.springframework.core.env.PropertySourcesPropertyResolver#getProperty(String key, ClasstargetValueType, boolean resolveNestedPlaceholders)。
在PropertySourcesPropertyResolver类的getProperty()方法中,会从 propertySources 资源中获取 key = xxx.xxx 的值,如果获取到一个对应的值,就会直接返回。其中,在propertySources中会封装PropertiesPropertySource、SystemEnvironmentPropertySource和ResourcePropertySource类型的对象,如图11-8所示。
其中,每种类型的对象中封装的信息如下所示。
- PropertiesPropertySource:封装 JVM 环境变量中的键值对。
- SystemEnvironmentPropertySource:封装操作系统环境变量中的键值对。
- ResourcePropertySource:封装项目中application.properties、yml和xml等文件中的键值对。
通过调试PropertySourcesPropertyResolver类的getProperty()方法,可以发现,ResourcePropertySource对象中获取到对应的值,如图11-9所示。
从ResourcePropertySource对象中获取到对应的值就可以设置到被@Value注解标注的字段上。
至此,使用@Value获取属性的值的源码流程分析完毕。
六、总结
@Value注解介绍完了,我们一起总结下吧!
本章,详细介绍了@Value注解,首先介绍了@Value注解的源码和使用场景,并且对@Value注解的用法进行了简单的介绍。随后,介绍了@Value的使用案例。接下来,从解析并获取 @Value 修饰的属性、为 @Value 修饰属性赋值和使用@Value获取属性值三个方面分别详细介绍了@Value注解在Spring底层执行的源码时序图和源码流程。
七、思考
既然学完了,就开始思考几个问题吧?
关于@Value注解,通常会有如下几个经典面试题:
- @Value注解的作用是什么?
- @Value注解有哪些使用场景?
- @Value向Bean的字段和方法注入值是如何实现的?
- @Value注解在Spring内部的执行流程?
- @Value注解在Spring源码中的执行流程与@Autowired注解有何区别?
- 你在平时工作中,会在哪些场景下使用@Value注解?
- 你从@Value注解的设计中得到了哪些启发?
文章转载自微服务:冰河技术
