Spring源码版本:4.3.23.RELEASE

一、加载XML配置

通过XML配置创建Spring,创建入口是使用org.springframework.context.support.ClassPathXmlApplicationContext类,创建容器的代码如下:

  1. package hello;
  2.  
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5.  
  6. public class HelloWorld
  7. {
  8. public static void main(String[] args) {
  9. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  10. System.out.println(context.getBean("hello.Dog", Dog.class).name);
  11. System.out.println(context.getBean("hello.Dog#0", Dog.class).name);
  12. }
  13. }
  14.  
  15. class Dog {
  16. String name = "PiPi";
  17. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6. <bean class="hello.Dog"/>
  7.  
  8. </beans>

1.1 如果bean没有配置id或name属性,那Spring会取class属性值(也就是全限定类名)加#index(index为bean对象在容器里的序号)作为name,取类全限定名作为别名aliases。具体看下面源码:

org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java#parseBeanDefinitionElement

  1. /**
  2. * Parses the supplied {@code <bean>} element. May return {@code null}
  3. * if there were errors during parse. Errors are reported to the
  4. * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
  5. */
  6. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
  7. String id = ele.getAttribute(ID_ATTRIBUTE);
  8. String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
  9.  
  10. List<String> aliases = new ArrayList<String>();
  11. if (StringUtils.hasLength(nameAttr)) {
  12. String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
  13. aliases.addAll(Arrays.asList(nameArr));
  14. }
  15.  
  16. String beanName = id;
  17. if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
  18. beanName = aliases.remove(0);
  19. if (logger.isDebugEnabled()) {
  20. logger.debug("No XML 'id' specified - using '" + beanName +
  21. "' as bean name and " + aliases + " as aliases");
  22. }
  23. }
  24.  
  25. if (containingBean == null) {
  26. checkNameUniqueness(beanName, aliases, ele);
  27. }
  28.  
  29. AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
  30. if (beanDefinition != null) {
  31. if (!StringUtils.hasText(beanName)) {
  32. try {
  33. if (containingBean != null) {
  34. beanName = BeanDefinitionReaderUtils.generateBeanName(
  35. beanDefinition, this.readerContext.getRegistry(), true);
  36. }
  37. else {
  38. beanName = this.readerContext.generateBeanName(beanDefinition); //获取到的bean名称为com.example.Hello#0这样的格式,#后面的数字为该类对象在进程中的编号。
  39. // Register an alias for the plain bean class name, if still possible,
  40. // if the generator returned the class name plus a suffix.
  41. // This is expected for Spring 1.2/2.0 backwards compatibility.
  42. String beanClassName = beanDefinition.getBeanClassName(); //获取class属性配置的bean的类名(全限定类名)
  43. if (beanClassName != null &&
  44. beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
  45. !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
  46. aliases.add(beanClassName); //使用全限定类名作为别名
  47. }
  48. }
  49. if (logger.isDebugEnabled()) {
  50. logger.debug("Neither XML 'id' nor 'name' specified - " +
  51. "using generated bean name [" + beanName + "]");
  52. }
  53. }
  54. catch (Exception ex) {
  55. error(ex.getMessage(), ele);
  56. return null;
  57. }
  58. }
  59. String[] aliasesArray = StringUtils.toStringArray(aliases);
  60. return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); //创建bean定义对象
  61. }
  62.  
  63. return null;
  64. }

1.2 Bean的定义加载到一个ConcurrentHashMap,key为bean名称,value为org.springframework.beans.factory.config.BeanDefinition:

org.springframework.beans.factory.support.DefaultListableBeanFactory#beanDefinitionMap

  1. /** Map of bean definition objects, keyed by bean name */
  2. private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition

  1. //---------------------------------------------------------------------
  2. // Implementation of BeanDefinitionRegistry interface
  3. //---------------------------------------------------------------------
  4.  
  5. @Override
  6. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  7. throws BeanDefinitionStoreException {
  8.  
  9. Assert.hasText(beanName, "Bean name must not be empty");
  10. Assert.notNull(beanDefinition, "BeanDefinition must not be null");
  11.  
  12. if (beanDefinition instanceof AbstractBeanDefinition) {
  13. try {
  14. ((AbstractBeanDefinition) beanDefinition).validate();
  15. }
  16. catch (BeanDefinitionValidationException ex) {
  17. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
  18. "Validation of bean definition failed", ex);
  19. }
  20. }
  21.  
  22. BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
  23. if (existingDefinition != null) {
  24. if (!isAllowBeanDefinitionOverriding()) {
  25. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
  26. "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
  27. "': There is already [" + existingDefinition + "] bound.");
  28. }
  29. else if (existingDefinition.getRole() < beanDefinition.getRole()) {
  30. // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
  31. if (logger.isWarnEnabled()) {
  32. logger.warn("Overriding user-defined bean definition for bean '" + beanName +
  33. "' with a framework-generated bean definition: replacing [" +
  34. existingDefinition + "] with [" + beanDefinition + "]");
  35. }
  36. }
  37. else if (!beanDefinition.equals(existingDefinition)) {
  38. if (logger.isInfoEnabled()) {
  39. logger.info("Overriding bean definition for bean '" + beanName +
  40. "' with a different definition: replacing [" + existingDefinition +
  41. "] with [" + beanDefinition + "]");
  42. }
  43. }
  44. else {
  45. if (logger.isDebugEnabled()) {
  46. logger.debug("Overriding bean definition for bean '" + beanName +
  47. "' with an equivalent definition: replacing [" + existingDefinition +
  48. "] with [" + beanDefinition + "]");
  49. }
  50. }
  51. this.beanDefinitionMap.put(beanName, beanDefinition);
  52. }
  53. else {
  54. if (hasBeanCreationStarted()) {
  55. // Cannot modify startup-time collection elements anymore (for stable iteration)
  56. synchronized (this.beanDefinitionMap) {
  57. this.beanDefinitionMap.put(beanName, beanDefinition);
  58. List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
  59. updatedDefinitions.addAll(this.beanDefinitionNames);
  60. updatedDefinitions.add(beanName);
  61. this.beanDefinitionNames = updatedDefinitions;
  62. if (this.manualSingletonNames.contains(beanName)) {
  63. Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
  64. updatedSingletons.remove(beanName);
  65. this.manualSingletonNames = updatedSingletons;
  66. }
  67. }
  68. }
  69. else {
  70. // Still in startup registration phase
  71. this.beanDefinitionMap.put(beanName, beanDefinition);
  72. this.beanDefinitionNames.add(beanName);
  73. this.manualSingletonNames.remove(beanName);
  74. }
  75. this.frozenBeanDefinitionNames = null;
  76. }
  77.  
  78. if (existingDefinition != null || containsSingleton(beanName)) {
  79. resetBeanDefinition(beanName);
  80. }
  81. }

Spring源码:Spring IoC容器加载过程(2)的更多相关文章

  1. Spring源码解析-ioc容器的设计

    Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...

  2. Spring源码:Spring IoC容器加载过程(1)

    Spring源码版本:4.3.23.RELEASE 一.加载过程概览 Spring容器加载过程可以在org.springframework.context.support.AbstractApplic ...

  3. Spring源码解析-IOC容器的实现-ApplicationContext

    上面我们已经知道了IOC的建立的基本步骤了,我们就可以用编码的方式和IOC容器进行建立过程了.其实Spring已经为我们提供了很多实现,想必上面的简单扩展,如XMLBeanFacroty等.我们一般是 ...

  4. SPRING源码分析:IOC容器

    在Spring中,最基本的IOC容器接口是BeanFactory - 这个接口为具体的IOC容器的实现作了最基本的功能规定 - 不管怎么着,作为IOC容器,这些接口你必须要满足应用程序的最基本要求: ...

  5. Spring源码分析:Bean加载流程概览及配置文件读取

    很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已 ...

  6. 【Spring源码分析】Bean加载流程概览

    代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...

  7. 【Spring源码分析】Bean加载流程概览(转)

    转载自:https://www.cnblogs.com/xrq730/p/6285358.html 代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. ...

  8. Tomcat8源码笔记(三)Catalina加载过程

    之前介绍过 Catalina加载过程是Bootstrap的load调用的  Tomcat8源码笔记(二)Bootstrap启动 按照Catalina的load过程,大致如下: 接下来一步步分析加载过程 ...

  9. Dubbo源码分析之ExtensionLoader加载过程解析

    ExtensionLoader加载机制阅读: Dubbo的类加载机制是模仿jdk的spi加载机制:  Jdk的SPI扩展加载机制:约定是当服务的提供者每增加一个接口的实现类时,需要在jar包的META ...

随机推荐

  1. RAM的分类

    转载自:http://wenku.baidu.com/view/b17d73244b35eefdc8d333ab.html RAM(随机存储器)可以分为SRAM(静态随机存储器)和DRAM(动态随机存 ...

  2. 非旋treap套线段树

    BZOJ3065. 去年用pascal 块链过了.. 今年来试了试非旋treap大法   注定被块链完爆 代码留这. 第一份 :辣鸡的  垃圾回收做法  跑得极慢 #include <bits/ ...

  3. eclipse 查找controller

    一.打开eclipse: 二.同时按住Ctrl + Shift + R ; 弹出框如下: 在红色输入框内输入controller 名字即可. 查找控制器里面的方法:Ctrl + O

  4. 单次目标检测器-SSD简介

    SSD 是使用 VGG19 网络作为特征提取器(和 Faster R-CNN 中使用的 CNN 一样)的单次检测器.我们在该网络之后添加自定义卷积层(蓝色),并使用卷积核(绿色)执行预测. 同时对类别 ...

  5. ubuntu下使用锐捷校园网

    前言           以下内容是个人学习之后的感悟,转载请注明出处~ 1.首先下载锐捷Linux版本,然后解压缩后,有个rjsupplicant.sh这个脚本文件,于是按照README做了,终端中 ...

  6. windows安装PHP5.4+Apache2.4+Mysql5.5

    windows安装PHP5.4+Apache2.4+Mysql5.5 作者:星之宇 ┊ 时间:2012-10-18 14:27 ┊ 分类: 网站技术 ┊ 阅读:1232 ┊ 评论:16 最近听说PHP ...

  7. Python_中__init__和__new__的异同

    1:__new__:它是创建对象时调用,会返回当前对象的一个实例: __init__:它是创建对象后调用,对当前对象的一些实例初始化,无返回值 代码示例: >>> class Dat ...

  8. Flutter实战视频-移动电商-40.路由_Fluro的全局注入和使用方法

    40.路由_Fluro的全局注入和使用方法 路由注册到顶层,使每个页面都可以使用,注册到顶层就需要在main.dart中 main.dart注册路由 注入 onGenerateRoute是Materi ...

  9. 洛谷 - P2257 - YY的GCD - 莫比乌斯反演 - 整除分块

    https://www.luogu.org/problemnew/show/P2257 求 \(n,m\) 中 \(gcd(i,j)==p\) 的数对的个数 求 $\sum\limits_p \sum ...

  10. UGUI 锚点坑

    ----------------------------------------------------------------- 关键点:4个实心蓝点距离雪花4瓣的距离永远不变 锚点Anchors: ...