Spring源码情操陶冶-PropertyPlaceholderBeanDefinitionParser注解配置解析器
本文针对spring配置的
context:property-placeholder
作下简单的分析,承接前文Spring源码情操陶冶-自定义节点的解析
spring配置文件应用
<context:property-placeholder location="classpath:context.properties">
PropertyPlaceholderBeanDefinitionParser-继承关系
配置文件解析类的继承关系如下
* AbstractBeanDefinitionParser
* AbstractSingleBeanDefinitionParser
* AbstractPropertyLoadingBeanDefinitionParser
* PropertyPlaceholderBeanDefinitionParser
所以我们将从父类开始慢慢剖析,方便理解的全面
AbstractBeanDefinitionParser-配置文件解析抽象类
直接查看主方法parse()
public final BeanDefinition parse(Element element, ParserContext parserContext) {
//模板方法,供子类调用,包装成AbstractBeanDefinition对象
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
//生成唯一id
String id = resolveId(element, definition, parserContext);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error(
"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
+ "' when used as a top-level tag", element);
}
String[] aliases = new String[0];
//解析context:property-holder的name属性,并支持,分隔
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
//包装为BeanDefinitionHolder对象
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
//注册到bean工厂中
registerBeanDefinition(holder, parserContext.getRegistry());
//执行事件
if (shouldFireEvents()) {
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
//目前为空
postProcessComponentDefinition(componentDefinition);
//保存至containingComponents栈中
parserContext.registerComponent(componentDefinition);
}
}
catch (BeanDefinitionStoreException ex) {
parserContext.getReaderContext().error(ex.getMessage(), element);
return null;
}
}
return definition;
}
主要的工作由子类AbstractSingleBeanDefinitionParser#parseInternal()
方法来处理
AbstractSingleBeanDefinitionParser#parseInternal-初始解析操作
此方法主要是初始化一些准备工作,并仍采用模板方法doParse()
方法供子类去实现解析操作
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
//类似于StringBuilder帮助创建beanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
//为null
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
//子类可复写此方法,譬如PropertyOverrideBeanDefinitionParser/PropertyPlaceholderBeanDefinitionParser
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
//设置beanClass
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
else {
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
if (parserContext.isNested()) {
// Inner bean definition must receive same scope as containing bean.
builder.setScope(parserContext.getContainingBeanDefinition().getScope());
}
//是否需要随spring上下文设置lazy-init属性
if (parserContext.isDefaultLazyInit()) {
// Default-lazy-init applies to custom bean definitions as well.
builder.setLazyInit(true);
}
//供子类调用实现解析,并传入BeanDefinitionBuilder对象
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
AbstractPropertyLoadingBeanDefinitionParser#doParse-基础解析
查看了下官方注释,对此类的解释是解析context:property-....
节点的抽象类,此处可指PropertyOverrideBeanDefinitionParser/PropertyPlaceholderBeanDefinitionParser
,可对此方法进行扩展,代码如下
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
//获取location属性,支持,分隔,表明指定读取配置文件的路径
String location = element.getAttribute("location");
if (StringUtils.hasLength(location)) {
String[] locations = StringUtils.commaDelimitedListToStringArray(location);
builder.addPropertyValue("locations", locations);
}
//获取properties-ref属性,设置properties文件的引用名
String propertiesRef = element.getAttribute("properties-ref");
if (StringUtils.hasLength(propertiesRef)) {
builder.addPropertyReference("properties", propertiesRef);
}
//获取file-encoding属性,文件解析字符编码集
String fileEncoding = element.getAttribute("file-encoding");
if (StringUtils.hasLength(fileEncoding)) {
builder.addPropertyValue("fileEncoding", fileEncoding);
}
//获取order属性,用于排序
String order = element.getAttribute("order");
if (StringUtils.hasLength(order)) {
builder.addPropertyValue("order", Integer.valueOf(order));
}
//获取ignore-resource-not-found属性,默认为false,表明找不到资源是否往外抛异常
builder.addPropertyValue("ignoreResourceNotFound",
Boolean.valueOf(element.getAttribute("ignore-resource-not-found")));
//获取local-override属性,默认为false,true表明先使用文件中的属性,找不到再使用环境变量中的属性
builder.addPropertyValue("localOverride",
Boolean.valueOf(element.getAttribute("local-override")));
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
}
PropertyPlaceholderBeanDefinitionParser-抽象方法的扩展
复写的抽象方法有两处,分别为getBeanClass()
和doParse()
方法
- getBeanClass(Element element)
指定解析文件的beanClass
,beanClass均是BeanFactoryPostProcessor
接口的实现类,代码如下
protected Class<?> getBeanClass(Element element) {
//获取system-properties-mode属性是否为ENVIRONMENT,是则采用PropertySourcesPlaceholderConfigurer.class
if (element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIB).equals(SYSTEM_PROPERTIES_MODE_DEFAULT)) {
return PropertySourcesPlaceholderConfigurer.class;
}
//默认为PropertyPlaceholderConfigurer.class作为beanClass
return PropertyPlaceholderConfigurer.class;
}
- doParse(Element element, BeanDefinitionBuilder builder)
在父类的基础上再加几个属性判断
protected void doParse(Element element, BeanDefinitionBuilder builder) {
super.doParse(element, builder);
//获取ignore-unresolvable属性,默认为false,true代表解析不了属性不抛异常
builder.addPropertyValue("ignoreUnresolvablePlaceholders",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
//获取system-properties-mode属性
String systemPropertiesModeName = element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIB);
if (StringUtils.hasLength(systemPropertiesModeName) &&
!systemPropertiesModeName.equals(SYSTEM_PROPERTIES_MODE_DEFAULT)) {
builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_"+systemPropertiesModeName);
}
}
小结
PropertyPlaceholderBeanDefinitionParser的作用是初始化配置文件的解析策略,方便spring在
invokeBeanFactoryPostProcessors()
中解析${}
属性使用,具体可看>>>Spring源码情操陶冶-AbstractApplicationContext#invokeBeanFactoryPostProcessors真正的解析
${}
这样格式的类是PropertyPlaceholderConfigurer.class
或者是PropertySourcesPlaceholderConfigurer.class
,前者适合spring 3.0之前,后者适合spring 3.1之后;
前者是默认的实现,后者如果指定local-override
为true,则优先找寻本地属性(文件属性),找不到的情况下再找寻环境属性(Environment)
context:property-placeholder
的属性
- location-文件资源路径,支持classpath路径,且可指定多个,以,分隔
- file-encoding-文件读取编码
- properties-ref-属性配置文件应用名
- order-排序属性
- ignore-resource-not-found-默认为false,表明找不到资源是否往外抛异常
- local-override-默认为false,表示优先查找文件(Properties)的属性,不存在则再找寻本地的属性(System),反之则是先本地后文件
- ignore-unresolvable-默认为false,true代表解析不了属性不抛异常
Spring源码情操陶冶-PropertyPlaceholderBeanDefinitionParser注解配置解析器的更多相关文章
- Spring源码情操陶冶-AnnotationConfigBeanDefinitionParser注解配置解析器
本文承接前文Spring源码情操陶冶-自定义节点的解析,分析spring中的context:annotation-config节点如何被解析 源码概览 对BeanDefinitionParser接口的 ...
- Spring源码情操陶冶-ComponentScanBeanDefinitionParser文件扫描解析器
承接前文Spring源码情操陶冶-自定义节点的解析,本文讲述spring通过context:component-scan节点干了什么事 ComponentScanBeanDefinitionParse ...
- Spring源码情操陶冶-AOP之ConfigBeanDefinitionParser解析器
aop-Aspect Oriented Programming,面向切面编程.根据百度百科的解释,其通过预编译方式和运行期动态代理实现程序功能的一种技术.主要目的是为了程序间的解耦,常用于日志记录.事 ...
- Spring源码情操陶冶-自定义节点的解析
本文承接前文Spring源码情操陶冶-DefaultBeanDefinitionDocumentReader#parseBeanDefinitions,特开辟出一块新地来啃啃这块有意思的骨头 自定义节 ...
- SpringMVC源码情操陶冶-ResourcesBeanDefinitionParser静态资源解析器
解析mvc:resources节点,控制对静态资源的映射访问 查看官方注释 /** * {@link org.springframework.beans.factory.xml.BeanDefinit ...
- Spring源码情操陶冶-AOP之Advice通知类解析与使用
阅读本文请先稍微浏览下上篇文章Spring源码情操陶冶-AOP之ConfigBeanDefinitionParser解析器,本文则对aop模式的通知类作简单的分析 入口 根据前文讲解,我们知道通知类的 ...
- Spring源码情操陶冶-tx:advice解析器
承接Spring源码情操陶冶-自定义节点的解析.本节关于事务进行简单的解析 spring配置文件样例 简单的事务配置,对save/delete开头的方法加事务,get/find开头的设置为不加事务只读 ...
- Spring源码情操陶冶#task:executor解析器
承接Spring源码情操陶冶-自定义节点的解析.线程池是jdk的一个很重要的概念,在很多的场景都会应用到,多用于处理多任务的并发处理,此处借由spring整合jdk的cocurrent包的方式来进行深 ...
- Spring源码情操陶冶-AbstractApplicationContext#finishBeanFactoryInitialization
承接前文Spring源码情操陶冶-AbstractApplicationContext#registerListeners 约定web.xml配置的contextClass为默认值XmlWebAppl ...
随机推荐
- BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758 01分数规划,所以我们对每个重心进行二分.于是问题转化为Σw[e]-mid>=0, ...
- A Bug's Life(种类并查集)(也是可以用dfs做)
http://acm.hdu.edu.cn/showproblem.php?pid=1829 A Bug's Life Time Limit:5000MS Memory Limit:327 ...
- POI实现大数据EXCLE导入导出,解决内存溢出问题
使用POI能够导出大数据保证内存不溢出的一个重要原因是SXSSFWorkbook生成的EXCEL为2007版本,修改EXCEL2007文件后缀为ZIP打开可以看到,每一个Sheet都是一个xml文件, ...
- 安装win8+Ubuntu14.04双系统的经验总结
当时查资料,很多人推荐了easyBCD直接安装ubuntu,但是在我的笔记本上行不通.我的笔记本是Lenovo V480+win8正版系统.这是因为我的笔记本的引导结构是EFI,而不是MBR.我的方法 ...
- [国嵌攻略][066][ARP协议实现]
以太网通讯 在计算机网络中,数据发送的过程就是把数据按照各层协议层层封装的过程.在这个过程中,最终要使用的协议通常是以太网协议(数据链路层协议). 以太网包格式 目的MAC地址:接收者的物理地址(6字 ...
- webpack运行常见错误归纳
今天在运行项目的时候,又遇到坑了,在公司运行的好好的项目,到我自己电脑上就报错,提示跨域,想了好久都不明白为啥,webpack配置文件里的ip地址我也改成与本地ip对应的,百思不得其解,在寻求别人帮助 ...
- 复选框之checked属性
今天无意中看到同事在学习复选框里面的checked属性的应用,当时看了一下,感觉熟悉而又陌生,发现checked属性其实还是挺奇怪的,感觉这里很有必要做一下笔记: 1.html中的checked属性. ...
- TP5.0 excel 导入导出
引第三方的phpexcel类库放到 ThinkPHP\Library\Vendor\demo下,自己建的文件夹demo 再将Excel.class放到ThinkPHP\Library\Org\clas ...
- SMTP错误码建议解决方法
https://wenku.baidu.com/view/0af30e01e87101f69e3195b8.html SMTP 错误码 / 建议解决方法 错误总表 101 Cannot Open Co ...
- phpstorm(或webstorm) 打开后 一直停留在scanning files to index....,或跳出内存不够的提示框
记得3月份做项目时就遇到过这个问题,当时解决的 ,但是忘记怎么解决的啦,所以 ,写博文是多么的重要啊. 说明: 在npm install 后,会出现Scanning files to index .. ...