网站常用文件夹,如何删除wordpress模板底部的签名,网页模板版权申请,如何给网站添加关键词之前写过一篇关于介绍Spring占位符替换原理的博客#xff0c;传送门 #xff1a;Spring的占位符是怎么工作的 在这篇文章基础上#xff0c;再介绍一下Value替换原理#xff0c;两篇文章有一定的相关性。
继续以上一篇的工程为例#xff0c;项目结构一样#xff0c;这里就…之前写过一篇关于介绍Spring占位符替换原理的博客传送门 Spring的占位符是怎么工作的 在这篇文章基础上再介绍一下Value替换原理两篇文章有一定的相关性。
继续以上一篇的工程为例项目结构一样这里就不再展示出来了详情可查看上一篇文章。 另外我定义了一个类内容如下
RestController
RequestMapping(/demo_client)
public class DemoClientController {// Value(${config.name})
// private String name;Value(${my.property.key})private String myPropertyName;
}希望从配置中拿到配置然后赋值给到myPropertyName属性。 说到赋值那肯定会想到spring的依赖注入DI很显然这个实现动态替换变量就是依赖注入原理完成的。Spring容器在启动过程中会先实例化对象然后初始化也就是填充对象属性。 Value注解属性填充它实现是通过一个叫AutowiredAnnotationBeanPostProcessor的bean前置处理器来完成的它是一个BeanPostProcessorSpring填充属性时候会调用其中postProcessProperties方法。
为什么是这个AutowiredAnnotationBeanPostProcessor类来处理的要从bean生命周期来说了这里不展开稍微提下 可以看到凡是Autowired和Value都是交给它来填充属性的。
好开始分析占位符变量替换过程. 工程启动后会进入到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean填充属性方法变量BeanPostProcessor其中就包含了AutowiredAnnotationBeanPostProcessor这个打开看看它里面有什么东西。 其中有个缓存的东西里面放了以beanName为keyValue是InjectionMetadata对象即需依赖注入的对象。这些依赖注入的对象是在方法 applyMergedBeanDefinitionPostProcessors执行时预先放进去的其实就是扫描解析所有带有AutowiredValueResourceInject等注解的bean然后缓存到此cache.以便后面填充属性时使用代码比较长需要花点时间看看。
因为我们定义的是DemoClientController所以找到它看看果然是有2个属性。 接着执行下一步进入此方法 开始填充属性myPropertyName 继续深入 最终会进入到此方法 其中embeddedValueResolvers是PropertySourcesPropertyResolver以及PropertySourcesPlaceholderConfigurer这两个对象是在属性填充之前已经准备好上一篇文章最开始加载配置资源的也有提到org.springframework.context.support.PropertySourcesPlaceholderConfigurer#postProcessBeanFactory方法具体看这个方法。
接着请求方法resolveStringValue所以会执行到PropertySourcesPlaceholderConfigurer的processProperties方法中去 这个方法上一篇文章已介绍过最终会执行到以下方法 然后拿到my.property.key的值最终spring容器会通过反射赋值到bean的属性即DemoClientController#myPropertyName赋值完成。
好了到这一步Value注解流程解析完成。
另外注意到上面的my.property.key配置我是把它放在dev.properties中的但在spring boot项目我们一般喜欢放在application-xx.yml中那么是不是流程会有区别 接着再分析下这种情况 先在application.yml定义一个名叫config.name的变量如下
server:port: 8999
spring:application:name: eureka-service-1
config:name: huangdDemoClientController稍微改动
RestController
RequestMapping(/demo_client)
public class DemoClientController {Value(${config.name})private String name;// Value(${my.property.key})
// private String myPropertyName;
}将myPropertyName注释改拿config.name配置。 跟之前一样启动工程前面一部分没有任何变化不同的地方在于 发现这时候不再是从namelocalProperties这个对象中拿配置而是从另外一个拿
是要从nameenvironmentProperties’中去拿配置因为application.yml的配置是放在它里面的。还有从上图看到发现它里面有9个对象都是干什么的我们不需要关心反正肯定是针对某个场景取不同的对象接着看它是从哪个对象拿配置的。上图看到执行到此方法这里这也说明就是从environment去拿的配置好继续往下走开始遍历上面9个对象找这个key为config.name的值最终是在 OriginTrackedMapPropertySource这里面找到了这个配置。 至于OriginTrackedMapPropertySource初始化是什么时候触发它是在这个地方初始化的应用启动时会执行到此步骤 拿到了配置值以后后面的流程跟之前一样了流程结束。
好了两种加载配置方式都已经分析完成大体上是一样的只是根据配置key所在不同的配置文件读取来源不一样。