Sring源码解析(一)Spring是怎么读取配置Xml文件的

简介: 1#Spring读取配置文件 ##Document在XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法中将Xml文件转换成Document对象;Document doc = doLoadDocument(inputSource, resource);

作者石臻臻, CSDN博客之星Top5Kafka Contributornacos Contributor华为云 MVP ,腾讯云TVP, 滴滴Kafka技术专家KnowStreaming, 《Kafka运维与实战宝典》电子书作者。 领取《Kafka运维与实战宝典》PDF请联系石臻臻


KnowStreaming  是滴滴开源的Kafka运维管控平台, 有兴趣一起参与参与开发的同学,但是怕自己能力不够的同学,可以联系我,当你导师带你参与开源!

1#Spring读取配置文件 ##Document

XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法中将Xml文件转换成Document对象;Document doc = doLoadDocument(inputSource, resource);20180428164047190.png

2Element


org.w3c.dom.Element 是一个接口 public interface Element extends NodeSpring中DefaultBeanDefinitionDocumentReader

@Override
 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
  this.readerContext = readerContext;
  logger.debug("Loading bean definitions");
  // 从Document中获取Element
  Element root = doc.getDocumentElement();
  //注册BeanDefinitions
  doRegisterBeanDefinitions(root);
 }

DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root)

protected void doRegisterBeanDefinitions(Element root) {
  BeanDefinitionParserDelegate parent = this.delegate;
  /**
  1.根据Element root创建**BeanDefinitionParserDelegate**对象
  2.解析Xml文件头中的一些属性配置到 BeanDefinitionParserDelegate属性(DocumentDefaultsDefinition)defaults;
  **/
  this.delegate = createDelegate(getReaderContext(), root, parent);
  //根据root查询 xml文件的命名空间是不是public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
  if (this.delegate.isDefaultNamespace(root)) {
   //省略.....
  }
  //默认空实现 子类可以重写这个方法来处理自定义xml文件
  preProcessXml(root);
  parseBeanDefinitions(root, this.delegate);
  //默认空实现 子类可以重写这个方法来处理自定义xml文件
  postProcessXml(root);
  this.delegate = parent;
 }

this.delegate = createDelegate(getReaderContext(), root, parent);里面调用 BeanDefinitionParserDelegate.initDefaults方法 1.初始化属性值private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition(); 2. TODO..

public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
  // this.defaults 是一个DocumentDefaultsDefinition对象;
  populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
  this.readerContext.fireDefaultsRegistered(this.defaults);
 }

BeanDefinitionParserDelegate.populateDefaults方法主要是讲xml文件中的一些命名空间的基本配置转换成DocumentDefaultsDefinition 对象; 例如

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"
 default-autowire="byName" default-lazy-init="false" default-dependency-check="all" >

//parentDefaults是父类的DocumentDefaultsDefinition对象
protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
  //查看xml文件中默认的default-lazy-init 值;(如果xml没有显示配置 则它的值为 default)懒加载的默认值
  String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
  if (DEFAULT_VALUE.equals(lazyInit)) {
   //如果有父类,则以父类的为准,否则将返回false。
   lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
  }
  defaults.setLazyInit(lazyInit);
  //default-autowire-candidates
  String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
  if (DEFAULT_VALUE.equals(merge)) {
   // Potentially inherited from outer <beans> sections, otherwise falling back to false.
   merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
  }
  defaults.setMerge(merge);
  //default-autowire
  String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
  if (DEFAULT_VALUE.equals(autowire)) {
   // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'.
   autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
  }
  defaults.setAutowire(autowire);
  // Don't fall back to parentDefaults for dependency-check as it's no longer supported in
  // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it.
  defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
  if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
   defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
  }
  else if (parentDefaults != null) {
   defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
  }
  if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
   defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
  }
  else if (parentDefaults != null) {
   defaults.setInitMethod(parentDefaults.getInitMethod());
  }
  if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
   defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
  }
  else if (parentDefaults != null) {
   defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
  }
  //这里是???
  defaults.setSource(this.readerContext.extractSource(root));
 }

3##DocumentDefaultsDefinition

DocumentDefaultsDefinition(文档的默认值定义)保存了 标准的Spring Xml文件中的 {@code beans}  层级的属性,这些属性是当前Xml配置中的默认全局属性值,例如  { @code default-lazy-init },{ @code default-autowire },等等。

例如:

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"
 default-autowire="byName" default-lazy-init="false" default-dependency-check="all" >

4###DefaultsDefinition

默认定义的标记接口,没有任何定义 ,只是单纯的标记一下;继承BeanMetadataElement类;通常具体的实现(例如DocumentDefaultsDefinition)是基于文档的默认值,例如在一个XML文档根标记级别来进行设置默认值

###BeanMetadataElement

需要被实现的元数据接口,这个接口定义了Object getSource()方法,返回一个配置源对象

public class DocumentDefaultsDefinition implements DefaultsDefinition {
 //初始化懒加载
 private String lazyInit;
 //
 private String merge;
 // 自动装载的类型 
 private String autowire;
 //
 private String dependencyCheck;
 private String autowireCandidates;
 //初始化方法
 private String initMethod;
 //销毁方法
 private String destroyMethod;
 //返回配置源对象
 private Object source;
 //省略 get set ......
}

default-autowire和autowire的可选值

可选值 功能说明
no 默认不使用autowiring。 必须显示的使用”“标签明确地指定bean。
byName 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。
byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置 dependency-check=”objects”让Spring抛出异常。
constructor 与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
autodetect 通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。

解析完了一些xml中Element的默认属性,接下来就是解析Element中的子属性了 DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(root, this.delegate);这个方法里我们主要看 delegate.parseCustomElement(ele);

 

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
  //获取命名空间
  String namespaceUri = getNamespaceURI(ele);
  //根据命名空间得到命名空间的处理类handler  如果是dubbo的uri 则返回的就是DubboNamespaceHandler
  //他们都继承自NamespaceHandlerSupport implements NamespaceHandler 
  //里面有调用了hander的init()...
  NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
  if (handler == null) {
   error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
   return null;
  }
  //1.根据Element的getLocalName()得到Element的name,然后根据这个name去NamespaceHandlerSupport中的一个属性为private final Map<String, BeanDefinitionParser> parsers ;中查找对应的解析器;这个解析器是什么时候被放到这个map里面的呢?TODO...
  //2.根据对应的解析器调用  .parse(element,parserContext)进行解析 
  return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
 }

5让我们来单独解析一下NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)首先了解一下 this.readerContext是BeanDefinitionParserDelegate中的一个属性private final XmlReaderContext readerContext;##XmlReaderContext

继承了ReaderContext类,并且提供了 对XmlBeanDefinitionReaderNamespaceHandlerResolver的访问权限;

public class XmlReaderContext extends ReaderContext {
 //可以看到 方法权限是private 的
 private final XmlBeanDefinitionReader reader;
 private final NamespaceHandlerResolver namespaceHandlerResolver;
 public XmlReaderContext(
   Resource resource, ProblemReporter problemReporter,
   ReaderEventListener eventListener, SourceExtractor sourceExtractor,
   XmlBeanDefinitionReader reader, NamespaceHandlerResolver namespaceHandlerResolver) {
  super(resource, problemReporter, eventListener, sourceExtractor);
  this.reader = reader;
  this.namespaceHandlerResolver = namespaceHandlerResolver;
 }
 //但是提供了一些访问的方法
 public final XmlBeanDefinitionReader getReader() {
  return this.reader;
 }
 public final BeanDefinitionRegistry getRegistry() {
  return this.reader.getRegistry();
 }
 public final ResourceLoader getResourceLoader() {
  return this.reader.getResourceLoader();
 }
 public final ClassLoader getBeanClassLoader() {
  return this.reader.getBeanClassLoader();
 }
 public final Environment getEnvironment() {
  return this.reader.getEnvironment();
 }
 public final NamespaceHandlerResolver getNamespaceHandlerResolver() {
  return this.namespaceHandlerResolver;
 }
  public String generateBeanName(BeanDefinition beanDefinition) {
  return this.reader.getBeanNameGenerator().generateBeanName(beanDefinition, getRegistry());
 }
 public String registerWithGeneratedName(BeanDefinition beanDefinition) {
  String generatedName = generateBeanName(beanDefinition);
  getRegistry().registerBeanDefinition(generatedName, beanDefinition);
  return generatedName;
 }
 public Document readDocumentFromString(String documentContent) {
  InputSource is = new InputSource(new StringReader(documentContent));
  try {
   return this.reader.doLoadDocument(is, getResource());
  }
  catch (Exception ex) {
   throw new BeanDefinitionStoreException("Failed to read XML document", ex);
  }
 }

1.那XmlReaderContext是什么时候被赋值的呢?我们顺着XmlReaderContext了解一下 ①. XmlBeanDefinitionReader.registerBeanDefinitions中被创建

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
  BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
  int countBefore = getRegistry().getBeanDefinitionCount();
  //创建XmlReaderContext,然后赋值给BeanDefinitionDocumentReader中readerContext属性中
  documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
  return getRegistry().getBeanDefinitionCount() - countBefore;
 }
public XmlReaderContext createReaderContext(Resource resource) {
  //this 最后就是 XmlReaderContext中的XmlBeanDefinitionReader属性
  return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
    this.sourceExtractor, this, getNamespaceHandlerResolver());
 }
 public NamespaceHandlerResolver getNamespaceHandlerResolver() {
  if (this.namespaceHandlerResolver == null) {
   this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
  }
  return this.namespaceHandlerResolver;
 }
 /**
 *如果没有具体的实现类,则创建 默认的实现类返回
 * 默认的实现类DefaultNamespaceHandlerResolver中的handlerMappingsLocation属性(Resource location to search for)=META-INF/spring.handlers
 */
 protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
  return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());
 }

②.创建后的XmlReaderContext被当做 BeanDefinitionParserDelegate 构造函数的参数来创建BeanDefinitionParserDelegate对象

protected void doRegisterBeanDefinitions(Element root) {
  BeanDefinitionParserDelegate parent = this.delegate;
  this.delegate = createDelegate(getReaderContext(), root, parent); 
  //省略.....
  }
目录
相关文章
|
8月前
|
存储 缓存 网络协议
阿里云特惠云服务器99元与199元配置与性能和适用场景解析:高性价比之选
2025年,阿里云长效特惠活动继续推出两款极具吸引力的特惠云服务器套餐:99元1年的经济型e实例2核2G云服务器和199元1年的通用算力型u1实例2核4G云服务器。这两款云服务器不仅价格亲民,而且性能稳定可靠,为入门级用户和普通企业级用户提供了理想的选择。本文将对这两款云服务器进行深度剖析,包括配置介绍、实例规格、使用场景、性能表现以及购买策略等方面,帮助用户更好地了解这两款云服务器,以供参考和选择。
|
8月前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
2126 1
|
6月前
|
域名解析 应用服务中间件 Shell
使用nps配置内网穿透加域名解析
使用nps配置内网穿透加域名解析
804 76
|
8月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
458 0
|
3月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
7月前
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
493 70
|
8月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
8月前
|
存储 监控 数据可视化
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
220 0
|
6月前
|
Android开发 开发者
Android自定义View之不得不知道的文件attrs.xml(自定义属性)
本文详细介绍了如何通过自定义 `attrs.xml` 文件实现 Android 自定义 View 的属性配置。以一个包含 TextView 和 ImageView 的 DemoView 为例,讲解了如何使用自定义属性动态改变文字内容和控制图片显示隐藏。同时,通过设置布尔值和点击事件,实现了图片状态的切换功能。代码中展示了如何在构造函数中解析自定义属性,并通过方法 `setSetting0n` 和 `setbackeguang` 实现功能逻辑的优化与封装。此示例帮助开发者更好地理解自定义 View 的开发流程与 attrs.xml 的实际应用。
176 2
Android自定义View之不得不知道的文件attrs.xml(自定义属性)

推荐镜像

更多
  • DNS