源码记录 5. 从Document到生成BeanDefinition并存入BeanFactory - Smile-Liu/spex GitHub Wiki

从Document到生成BeanDefinition并存入BeanFactory

  1. 在XmlBeanDefinitionReader中的registerBeanDefinitions方法中进行解析和注册 首先,生成BeanDefinitionDocumentReader 然后,调用其的registerBeanDefinitions方法

  2. 接下来就转入BeanDefinitionDocumentReader类了 会生成一个BeanDefinitionParseDelegate,用作解析的工具代理

  3. 判断Element的namespace是否是默认的,是则继续,不是则转入自定义解析方法(不做自定义解析)

  4. 判断Element的标签名称,Spring支持bean、beans、alias、import(以下主要叙述bean的解析)

  5. 以class属性和parent属性值来new GenericBeanDefinition 如果指定了classloader,则setClassLoader,否则设置class属性值到beanClassName属性中

  6. 解析bean标签的属性值 包括:

scope(放入scope属性)
abstract(放入abstract属性)
lazy-init(放入lazyInit属性)
autowire(放入autowireMode属性)
depends-on(放入dependsOn属性)
autowire-candidate(放入autowireCandidate属性)
primary(放入primary属性)
init-method(放入initMethod属性)
destroy-method(放入destroyMethod属性)
factory-method(放入factoryMethod属性)
factory-bean(放入factoryBean属性)
  1. 解析bean标签的子标签meta,放入AbstractBeanDefinition的父类AttributeAccessorSupport中的attribute(map)中

  2. 解析bean标签的子标签lookup-method,放入methodOverrides属性中

lookup-method是获取器注入,
其name属性为返回某种类型bean的方法名,bean属性为具体返回的bean。旨在解除程序耦合,实现可插拔式功能
  1. 解析bean标签的子标签replaced-method,也放入methodOverrides属性中
replaced-method是方法替换,可以在运行时用新方法替换现有方法。
其name属性为bean中的方法名称,replacer属性为实现了MethodReplacer接口的类
  1. 解析bean标签的子标签constructor-arg,放入constructorArgumentValues属性中
constructor-arg是构造器参数,有两种注入方式:指定index和不指定index。
如果是指定index,则会把解析的元素值存入ConstructorArgumentValues类的indexedArgumentValues(map)中,
否则存入genericArgumentValues(list)中。
由于constructor-arg标签既可以做父标签,又可以直接指定ref或value,
所以可以按照property标签的方式来解析。
另外,constructor-arg可以指定type和name属性
  1. 解析bean标签的子标签property,放入propertyValues属性中
ref属性、value属性以及property标签的子标签,三者只能有一个。
如果是ref或value,则直接把属性值计入propertyValues即可,
如果是子标签(有bean、ref、idref、value、null、array、list、set、map、props),则分别解析并计入propertyValues
  1. 解析bean标签的子标签qualifier,放入qualifiers(map,key是type属性)属性中
qualifier属性用来指定注入指定类型bean的名称,旨在消除同一个类有多个实例时的冲突
  1. 解析工作至此完成。然后设置beanName
首先,取到bean标签的id属性值,
如果该属性有值,则beanName就是该属性值;如果没值或者没有该属性,则要自动生成一份
然后,拿到BeanDefinition的beanClassName属性值(如果有beanClass,则会使用该属性的值),
如果拿不到,则再查看是否有parent属性值,有则beanName指定为parent+”$child”,
没有则继续查看是否有factory-bean属性值,有则beanName指定为factory-bean+”$created”。
如果到现在还没有则会报错。
如果不是子bean,而且已经存在beanName,则会发个序号加在后面
  1. 使用beanName,以及解析完成的AbstractBeanDefinition,生成BeanDefinitionHolder

  2. 如果需要则进行装饰()

  3. 把BeanDefinitionHolder注册到BeanFactory中(参数是父接口BeanDefinitionRegistry,其实是DefaultListableBeanFactory)

首先对BeanDefinition做最后的校验:methodoverrides和factorymethod不能共存
其次对整个beanDefinitionMap进行synchronized
然后校验beanName是否已经存在,如果存在,并不允许覆盖的话(默认允许),则要报错
最后把beanName和BeanDefinition放入beanDefinitionMap,并把beanName放入beanDefinitionNames中

接着,在SimpleAliasRegistry中对别名进行注册,放入aliasMap(key是每个alias,value是beanName)
  1. 完成

  2. BeanDefinition的类图 BeanDefinition的类图.png

  3. 读取BeanDefinition的工具类图 工具类图.png