1、DefaultListableBeanFactory

1.1 类的结构

image.png
DefaultListableBeanFactory是整个bean加载的核心部分,是Spring注册及加载的bean的默认实现。DefaultListableBeanFactory继承了AbstractAutowireCapableBeanFactory并实现了ConfigurableListableBeanFactory以及BeanDefinitionRegistry接口。

  1. public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
  2. implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable

1.2 XmlBeanFactory

XmlBeanFactory对父类DefaultListableBeanFactory进行了扩展,主要用于从XML文档中读取BeanDefinition,对于注册及获取bean都是使用从父类DefaultListableBeanFactory继承的方法区实现,而唯独与父类不同的个性化实现就是增加了XmlBeanDefinitionReader类型的reader属性。在XmlBeanFactory中主要使用reader属性对资源文件进行读取和注册;

  1. //## 对资源文件进行读取和注册 ##//
  2. private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

1.2.1 XmlBeanDefinitionReader

  • 继承AbstractBeanDefinitionReader中的方法,来使用ResourceLoader将资源文件路径转换为对应的Resource文件。
  • 通过DocumentLoader对Resource文件进行转换,将Resource文件转换为Document文件。
  • 通过实现接口BeanDefinitionDocumentReader的DefaultBeanDefinitionDocumentReader对Document进行解析,并使用BeanDefinitionParserDelegate对Element进行解析。

1.3ClassPathResource

Spring的配置文件读取是通过ClassPathResource进行封装的。
Spring对其内部使用到的资源实现了自己的抽象结构:Resource接口封装底层资源。
image.png
当通过Resource相关类完成了对配置文件进行封装后,配置文件的读取功能就全权交给XmlBeanDefinitionReader来处理了。

2、源码

  1. public XmlBeanFactory(Resource resource) throws BeansException {
  2. //调用XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)构造方法
  3. this(resource, null);
  4. }
  1. public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
  2. //parentBeanFactory为父类BeanFactory用于factory合并,可以为空
  3. super(parentBeanFactory);
  4. //资源加载的真正实现
  5. this.reader.loadBeanDefinitions(resource);
  6. }

2.1 核心逻辑部分loadBeanDefinitions

封装资源文件。当进入XmlBeanDefinitionReader后首先对参数Resource使用EncodedResource类进行封装。

  1. /**
  2. * Load bean definitions from the specified XML file.
  3. * @param resource the resource descriptor for the XML file
  4. * @return the number of bean definitions found
  5. * @throws BeanDefinitionStoreException in case of loading or parsing errors
  6. */
  7. @Override
  8. public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
  9. //## 1、封装资源文件 ##//
  10. return loadBeanDefinitions(new EncodedResource(resource));
  11. }

获取输入流。从Resource中获取对应的InputStream并构造InputSource。
通过构造的InputSource实例和Resource实例继续调用函数doLoadBeanDefinitions。

  1. public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
  2. Assert.notNull(encodedResource, "EncodedResource must not be null");
  3. if (logger.isInfoEnabled()) {
  4. logger.info("Loading XML bean definitions from " + encodedResource);
  5. }
  6. //## 通过属性来记录已经加载的资源 ##//
  7. Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
  8. if (currentResources == null) {
  9. currentResources = new HashSet<>(4);
  10. this.resourcesCurrentlyBeingLoaded.set(currentResources);
  11. }
  12. if (!currentResources.add(encodedResource)) {
  13. throw new BeanDefinitionStoreException(
  14. "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
  15. }
  16. try {
  17. //## 2、获取输入流 ##//
  18. InputStream inputStream = encodedResource.getResource().getInputStream();
  19. try {
  20. //## 2.1 构造InputSource实例 ##//
  21. //## InputSource这个类并不来自于Spring,它的全路径是 org.xml.sax.InputSource ##//
  22. InputSource inputSource = new InputSource(inputStream);
  23. if (encodedResource.getEncoding() != null) {
  24. inputSource.setEncoding(encodedResource.getEncoding());
  25. }
  26. //## 3、通过InputSource实例和Resource实例继续调用函数 ##//
  27. //## 真正进入了逻辑核心部分 ##//
  28. return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
  29. }
  30. finally {
  31. //## 关闭输入流 ##//
  32. inputStream.close();
  33. }
  34. }
  35. catch (IOException ex) {
  36. throw new BeanDefinitionStoreException(
  37. "IOException parsing XML document from " + encodedResource.getResource(), ex);
  38. }
  39. finally {
  40. currentResources.remove(encodedResource);
  41. if (currentResources.isEmpty()) {
  42. this.resourcesCurrentlyBeingLoaded.remove();
  43. }
  44. }
  45. }

2.1 核心处理部分doLoadBeanDefinitions

  • 获取对XML文件的验证模式
  • 加载XML文件,并得到相应的Document
  • 根据返回的Document注册Bean信息

    1. protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    2. throws BeanDefinitionStoreException {
    3. try {
    4. //## 1、getValidationModeForResource 获取XML文件的验证模式 ##//
    5. //## 2、加载XML文件,并得到对应Document ##//
    6. Document doc = doLoadDocument(inputSource, resource);
    7. //## 根据返回的Document注册Bean信息 ##//
    8. return registerBeanDefinitions(doc, resource);
    9. }
    10. catch (BeanDefinitionStoreException ex) {
    11. throw ex;
    12. }
    13. catch (SAXParseException ex) {
    14. throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    15. "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
    16. }
    17. catch (SAXException ex) {
    18. throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    19. "XML document from " + resource + " is invalid", ex);
    20. }
    21. catch (ParserConfigurationException ex) {
    22. throw new BeanDefinitionStoreException(resource.getDescription(),
    23. "Parser configuration exception parsing XML from " + resource, ex);
    24. }
    25. catch (IOException ex) {
    26. throw new BeanDefinitionStoreException(resource.getDescription(),
    27. "IOException parsing XML document from " + resource, ex);
    28. }
    29. catch (Throwable ex) {
    30. throw new BeanDefinitionStoreException(resource.getDescription(),
    31. "Unexpected exception parsing XML document from " + resource, ex);
    32. }
    33. }
    1. public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    2. //## 使用DefaultBeanDefinitionDocumentReader 实例化 BeanDefinitionDocumentReader ##//
    3. BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    4. //## 记录统计前 BeanDefinition 的加载个数 ##//
    5. int countBefore = getRegistry().getBeanDefinitionCount();
    6. //## 加载及注册bean BeanDefinitionDocumentReader是一个接口,真正的类型其实已经是DefaultBeanDefinitionDocumentReader ##//
    7. documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    8. //## 记录本次加载 BeanDefinition 的个数 ##//
    9. return getRegistry().getBeanDefinitionCount() - countBefore;
    10. }

    2.3核心逻辑的底部doRegisterBeanDefinitions

    1. protected void doRegisterBeanDefinitions(Element root) {
    2. // Any nested <beans> elements will cause recursion in this method. In
    3. // order to propagate and preserve <beans> default-* attributes correctly,
    4. // keep track of the current (parent) delegate, which may be null. Create
    5. // the new (child) delegate with a reference to the parent for fallback purposes,
    6. // then ultimately reset this.delegate back to its original (parent) reference.
    7. // this behavior emulates a stack of delegates without actually necessitating one.
    8. BeanDefinitionParserDelegate parent = this.delegate;
    9. //## 专门处理解析BeanDefinitionParserDelegate类型的实例 ##//
    10. this.delegate = createDelegate(getReaderContext(), root, parent);
    11. if (this.delegate.isDefaultNamespace(root)) {
    12. //## 处理profile属性 ##//
    13. String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
    14. if (StringUtils.hasText(profileSpec)) {
    15. String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
    16. profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    17. if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    18. if (logger.isInfoEnabled()) {
    19. logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
    20. "] not matching: " + getReaderContext().getResource());
    21. }
    22. return;
    23. }
    24. }
    25. }
    26. //## 解析处理处理,留给子类实现 ##//
    27. preProcessXml(root);
    28. //## 解析并注册bean ##//
    29. parseBeanDefinitions(root, this.delegate);
    30. //## 解析后处理,留给子类实现 ##//
    31. postProcessXml(root);
    32. this.delegate = parent;
    33. }

    2.4 解析并注册BeanDefinition

    1. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    2. if (delegate.isDefaultNamespace(root)) {
    3. NodeList nl = root.getChildNodes();
    4. for (int i = 0; i < nl.getLength(); i++) {
    5. Node node = nl.item(i);
    6. if (node instanceof Element) {
    7. Element ele = (Element) node;
    8. if (delegate.isDefaultNamespace(ele)) {
    9. //## 对bean处理 默认解析 ##//
    10. parseDefaultElement(ele, delegate);
    11. }
    12. else {
    13. //## 对bean处理 自定义解析 ##//
    14. delegate.parseCustomElement(ele);
    15. }
    16. }
    17. }
    18. }
    19. else {
    20. delegate.parseCustomElement(root);
    21. }
    22. }

    2.4.1 默认标签的解析

    1. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    2. //## 对import标签的处理 ##//
    3. if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
    4. importBeanDefinitionResource(ele);
    5. }
    6. //## 对alias标签的处理 ##//
    7. else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
    8. processAliasRegistration(ele);
    9. }
    10. //## 对bean标签的处理 ##//
    11. else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
    12. processBeanDefinition(ele, delegate);
    13. }
    14. //## 对beans标签的处理 ##//
    15. else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
    16. // recurse
    17. doRegisterBeanDefinitions(ele);
    18. }
    19. }
  • bean标签的解析及注册

  1. 首先委托BeanDefinitionParserDelegate类的方法parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder类型的实例bdHolder(包含我们配置文件的各种属性,如:class、name、id、alias之类的属性)。
  2. 当返回的bdHolder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要对自定义标签再次解析。
  3. 解析完成后,需要对解析后的bdHolder进行注册。
  4. 最后发出响应事件。

    1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    2. //## 委托BeanDefinitionParserDelegate类的方法parseBeanDefinitionElement进行元素解析 ##//
    3. //## BeanDefinitionHolder的实例bdHolder 已经包含我们配置文件中配置的各种属性了,例如:class、name、id、alias ##//
    4. BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    5. if (bdHolder != null) {
    6. //## 若存在默认标签的子节点下再有自定义属性,还需要对自定义属性进行解析 ##//
    7. bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    8. try {
    9. // Register the final decorated instance.
    10. //## 解析完成后,需要对bdHolder进行注册 ##//
    11. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    12. }
    13. catch (BeanDefinitionStoreException ex) {
    14. getReaderContext().error("Failed to register bean definition with name '" +
    15. bdHolder.getBeanName() + "'", ele, ex);
    16. }
    17. // Send registration event.
    18. //## 通知监听器解析及注册完成 ##//
    19. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    20. }
    21. }

    2.4.1.1 创建用于属性承载的BeanDefinition

    BeanDefinition是一个接口,在Spring中存在三种实现,RootBeanDefinition、ChildBeanDefinition以及GenericBeanDefinition。三种实现均继承AbstractBeanDefinition,其中BeanDefinition是配置文件元素标签在容器中的内部标识形式。

    2.4.1.2 注册解析的BeanDefinition

    1. public static void registerBeanDefinition(
    2. BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    3. throws BeanDefinitionStoreException {
    4. // Register bean definition under primary name.
    5. //## 使用beanName做唯一标识注册 ##//
    6. String beanName = definitionHolder.getBeanName();
    7. registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    8. // Register aliases for bean name, if any.
    9. //## 注册所以别名 ##//
    10. String[] aliases = definitionHolder.getAliases();
    11. if (aliases != null) {
    12. for (String alias : aliases) {
    13. registry.registerAlias(beanName, alias);
    14. }
    15. }
    16. }
  5. 通过beanName注册BeanDefinition

  6. 通过别名注册BeanDefinition

    2.4.1.3 通知监听器解析及注册完成

2.4.2 自定义标签的解析