搜索
房产
装修
汽车
婚嫁
健康
理财
旅游
美食
跳蚤
二手房
租房
招聘
二手车
教育
茶座
我要买房
买东西
装修家居
交友
职场
生活
网购
亲子
情感
龙城车友
找美食
谈婚论嫁
美女
兴趣
八卦
宠物
手机

曹工说Spring Boot源码(9)-- Spring解析xml文件,到底从中得到了什么(co

[复制链接]
查看: 91|回复: 0

1万

主题

1万

帖子

3万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
32673
发表于 2020-1-15 00:26 | 显示全部楼层 |阅读模式
写在前面的话

相关背景及资本:
曹工说Spring Boot源码(1)-- Bean Definition究竟是什么,附spring脑筋导图分享
曹工说Spring Boot源码(2)-- Bean Definition究竟是什么,我们对着接口,逐一方式讲授
曹工说Spring Boot源码(3)-- 手动注册Bean Definition不比游戏好玩吗,我们来试一下
曹工说Spring Boot源码(4)-- 我是怎样自界说ApplicationContext,从json文件读取bean definition的?
曹工说Spring Boot源码(5)-- 怎样从properties文件读取bean
曹工说Spring Boot源码(6)-- Spring怎样从xml文件里分解bean的
曹工说Spring Boot源码(7)-- Spring分解xml文件,到底从中获得了什么(上)
曹工说Spring Boot源码(8)-- Spring分解xml文件,到底从中获得了什么(util命名空间)
工程代码地点 脑筋导图地点
工程结构图:
曹工说Spring Boot源码(9)-- Spring解析xml文件,到底从中得到了什么(co  热点新闻 519126-20191215144930717-1919774390

提要

先给大家看看spring支持的xml设备,我列了个表格以下:
namespaceelementutilconstant、property-path、list、set、map、propertiescontextproperty-placeholder、property-override、annotation-config、component-scan、load-time-weaver、spring-configured、mbean-export、mbean-serverbeansimport、bean、aliastaskannotation-driven、scheduler、scheduled-tasks、executorcacheadvice、annotation-drivenaopconfig、scoped-proxy、aspectj-autoproxy我题目标意义是,spring在分解每个差此外xml元素时,实在是有共性的。全数这些元素的分解器,都实现了BeanDefinitionParser。这个接口只要一个方式,感化就是分解元素时,按照元素的设备,来收集beanDefinition,正所谓:条条大道通罗马,各类xml设备元素,各类注解设备,就是那些大道,罗马是什么?
就是beanDefinition。
从第一篇到现在,已经第9篇了,我们还在讲bean definition,实在就是由于,只要深上天大白了它,背面才华更方便地大白spring boot,大白configuration注解,大白enable,大白自动装配。
好了,切入本篇,本篇要讲授的xml元素是context命名空间里的。
context:property-placeholder

用法
  1.                     
复制代码
  1. @Datapublic class TestPropertiesVO {    private String name;}   
复制代码
  1. #application.propertiesname: Phil
复制代码
测试代码:
  1. package org.springframework.contextnamespace;import com.alibaba.fastjson.JSONObject;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.config.BeanDefinition;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.springframework.util.MyFastJson;import java.util.List;import java.util.Map;@Slf4jpublic class TestPropertyPlaceholder {    public static void main(String[] args) {        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(                new String[]{"classpath:context-namespace-test-property-holder.xml"},false);        context.refresh();        Map map = context.getDefaultListableBeanFactory().getAllSingletonObjectMap();        log.info("singletons:{}", JSONObject.toJSONString(map));        List list =                context.getBeanFactory().getBeanDefinitionList();        MyFastJson.printJsonStringForBeanDefinitionList(list);        // 获得该bean,打印        Object bean = context.getBean(TestPropertiesVO.class);        System.out.println("bean:" + bean);    }}
复制代码
输出以下:
  1. bean:TestPropertiesVO(name=Phil)
复制代码
假如我们点窜xml:
  1.     //诠释之,看看会怎样                    
复制代码
输出以下:
  1. bean:TestPropertiesVO(name=${name})
复制代码
可以看到,这样子呢,就没法分解到properties中的值了。
等价用法
  1.             // 这个设备方式,和上面那个,结果实在是一样的;上面那个,是对下边这类的封装                                        classpath:application.properties                                       
复制代码
元素分解

我们切入到org.springframework.context.config.ContextNamespaceHandler,查找下该元素的分解器。
  1. public class ContextNamespaceHandler extends NamespaceHandlerSupport {    public void init() {        registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());        registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());        registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());        registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());        registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());        registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());        registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());    }}
复制代码
我们可以看到,本元素的分解器是:PropertyPlaceholderBeanDefinitionParser。
先看看类继续结构:
曹工说Spring Boot源码(9)-- Spring解析xml文件,到底从中得到了什么(co  热点新闻 519126-20200113224612904-1414064030

大家留意第三层,类名里,有Single字样,说大白它是单身狗?不是。说明这个xml元素分解器,终极只获得一个bean definition。
第四层的AbstractPropertyLoadingBeanDefinitionParser,就是供给一个笼统类,提取一些和对应的分解器中公共的方式。
可以简单一看:
  1. abstract class AbstractPropertyLoadingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {   @Override   protected boolean shouldGenerateId() {      return true;   }      // 获得一些属性   @Override   protected void doParse(Element element, BeanDefinitionBuilder builder) {      String location = element.getAttribute("location");      if (StringUtils.hasLength(location)) {         String[] locations = StringUtils.commaDelimitedListToStringArray(location);         builder.addPropertyValue("locations", locations);      }      String propertiesRef = element.getAttribute("properties-ref");      if (StringUtils.hasLength(propertiesRef)) {         builder.addPropertyReference("properties", propertiesRef);      }      String fileEncoding = element.getAttribute("file-encoding");      if (StringUtils.hasLength(fileEncoding)) {         builder.addPropertyValue("fileEncoding", fileEncoding);      }      String order = element.getAttribute("order");      if (StringUtils.hasLength(order)) {         builder.addPropertyValue("order", Integer.valueOf(order));      }      builder.addPropertyValue("ignoreResourceNotFound",            Boolean.valueOf(element.getAttribute("ignore-resource-not-found")));      builder.addPropertyValue("localOverride",            Boolean.valueOf(element.getAttribute("local-override")));          builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);   }}
复制代码
看了父,不看正主也说不外去,这里呢,正主是真的简单:
  1. class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {   private static final String SYSTEM_PROPERTIES_MODE_ATTRIB = "system-properties-mode";   private static final String SYSTEM_PROPERTIES_MODE_DEFAULT = "ENVIRONMENT";      // 这里获得bean的class,留意,这里的class,能否是和前面:等价用法那一节里,设备的bean的class一样   // 所以啊,context:property-placeholder和等价用法里的底层实现,还是一样的   @Override   protected Class getBeanClass(Element element) {      ...      return PropertyPlaceholderConfigurer.class;   }   @Override   protected void doParse(Element element, BeanDefinitionBuilder builder) {      super.doParse(element, builder);      builder.addPropertyValue("ignoreUnresolvablePlaceholders",            Boolean.valueOf(element.getAttribute("ignore-unresolvable")));      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);      }   }}
复制代码
大家可以看诠释,这里返回的class,和等价用法里的的class是千篇同等。说大白什么呢?大家这么聪明,不用我多说了。
这个class,PropertyPlaceholderConfigurer,实在还是比力特此外,我们看看其类图:
曹工说Spring Boot源码(9)-- Spring解析xml文件,到底从中得到了什么(co  热点新闻 519126-20200114223959512-842398281

这里,我们发现这个bean class,居然是一个BeanFactoryPostProcessor。这个接口有什么感化呢,大要就是,等全数的beanDefinition都装载了以后,会挪用实现了BeanFactoryPostProcessor接口的bean,对beanDefinition举行处置惩罚。
假如对这块感爱好,可以看博主之前的一篇文章,网上也很多分解,可自行搜索:
曹工杂谈:为什么很少必要改Spring源码,由于扩大点太多了,说说Spring的后置处置惩罚器
context:property-override

用法

这个元素,一样平常比力少用,但本日查了一下,我以为这个还比力故意义,而且很奇妙地和当前spring boot内部化设备的脑筋合适。
它的用处说起来比力艰涩,我们看例子就晓得了:
  1.                                 
复制代码
  1. package org.springframework.contextnamespace;import lombok.Data;@Datapublic class Person {    private String name;    private int age;    private String location;}
复制代码
测试代码:
  1. package org.springframework.contextnamespace;import com.alibaba.fastjson.JSONObject;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.config.BeanDefinition;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.springframework.util.MyFastJson;import java.util.List;import java.util.Map;/** * desc: * * @author : caokunliang * creat_date: 2019/12/25 0025 * creat_time: 15:50 **/@Slf4jpublic class TestPropertyOverride {    public static void main(String[] args) {        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(                new String[]{"classpath:context-namespace-test-property-override.xml"},false);        context.refresh();        // 获得bean        Object bean = context.getBean(Person.class);        System.out.println("bean:" + bean);    }}
复制代码
输出以下:
bean:Person(name=Ram, age=20, location=Varanasi)
这个应当大家都懂。
接下来,我们在xml里界说一个元素:
  1.         // 设备了这个玩意                                    
复制代码
  1. #beanOverride.properties person.age=40person.location=Delhi
复制代码
测试步伐安定,此次的输出以下:
bean:Person(name=Ram, age=40, location=Delhi)
也就是说,内部设备文件:beanOverride.properties中的属性,覆盖了xml中的bean的属性。
而现在,spring boot的environment分解变量时,也是内部的设备文件、命令行参数、情况变量等,优先级高于jar包内的设备,能否是和我们这个元素的感化比力像呢?
等价用法

假如不利用:,也可以像下面这样利用:
  1.      
复制代码
元素分解

从ContextNamespaceHandler,我们可以找到该元素对应的parser:PropertyOverrideBeanDefinitionParser
  1. public void init() {   registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());   registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());   registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());   registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());   registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());   registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());   registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());   registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());}
复制代码
类实现也很简单,和前面的一样,都继续了同一个基类:AbstractPropertyLoadingBeanDefinitionParser。
简单看看实在现吧:
  1. class PropertyOverrideBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {    @Override    protected Class getBeanClass(Element element) {        return PropertyOverrideConfigurer.class;    }    @Override    protected void doParse(Element element, BeanDefinitionBuilder builder) {        super.doParse(element, builder);        builder.addPropertyValue("ignoreInvalidKeys",                Boolean.valueOf(element.getAttribute("ignore-unresolvable")));    }}
复制代码
这里,看看我们获得的bean class:
曹工说Spring Boot源码(9)-- Spring解析xml文件,到底从中得到了什么(co  热点新闻 519126-20200114224325336-1580466525

和前面会商的一样,也是一个BeanFactoryPostProcessor。
总结

又必要答复题目标题目了,从xml文件里,分解获得了什么呢,答案仍然是beanDefinition。
不外呢,此次的beanClass,略有不同,由于他们是特此外class,是可以参加beanDefinition生命周期的class,
由于他们实现了BeanFactoryPostProcessor。
大家可以再看看前面util命名空间,那些bean class呢,重要就是FactoryBean。
本篇源码位置:
https://gitee.com/ckl111/spring-boot-first-version-learn/tree/master/all-demo-in-spring-learning/spring-xml-demo/src/main/java/org/springframework/contextnamespace
由于context命名空间都是些大人物,所以本篇重如果先给大家热身,下一讲,我们讲讲这里面的:
  1. annotation-config、component-scan
复制代码
我简单看了两眼,还挺故意义,接待大家和我一路进修。

免责声明:假如加害了您的权益,请联系站长,我们会实时删除侵权内容,感谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Copyright © 2006-2014 全椒百姓网-全椒知名**,发布及时新鲜的全椒新闻资讯 生活信息 版权所有 法律顾问:高律师 客服电话:0791-88289918
技术支持:迪恩网络科技公司  Powered by Discuz! X3.2
快速回复 返回顶部 返回列表