核心子方法2: obtainFreshBeanFactory()方法详解

先总结: 该方法new了一个beanFactory, 设置了一些忽略的接口, 加载并解析了bean.xml, 主要将bean信息解析为BeanDefinition保存到beanFactory中

1.refreshBeanFactory()方法

   1.1 创建DefaultListableBeanFactory对象: createBeanFactory() -> new DefaultListableBeanFactory(getInternalParentBeanFactory());

  1.2 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖: customizeBeanFactory(beanFactory);

 

   1.3 初始化documentReader,并进行XML文件读取及解析,默认命名空间的解析,自定义标签的解析: loadBeanDefinitions(beanFactory);  注意: 解析xml核心方法

    创建一个xml的beanDefinitionReader,并通过回调设置到beanFactory中:

      XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory)

    给reader对象设置环境对象: beanDefinitionReader.setEnvironment(this.getEnvironment());

    beanDefinitionReader.setResourceLoader(this);

    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    初始化beanDefinitionReader对象,此处设置配置文件是否要进行验证: initBeanDefinitionReader(beanDefinitionReader);

    始完成beanDefinition的加载: loadBeanDefinitions(beanDefinitionReader);

      通过XmlBeanDefinitionReader对象, 遍历加载所有xml配置文件:

       loadBeanDefinitions

      -> loadBeanDefinitions(new EncodedResource(resource));

      -> doLoadBeanDefinitions(inputSource, encodedResource.getResource());  //xml解析核心步骤

      -> Document doc = doLoadDocument(inputSource, resource);  //获取xml文件的document对象

        int count = registerBeanDefinitions(doc, resource);  //解析document对象, 封装成一个个的BeanDefinition对象

      -> BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();

        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

      -> doRegisterBeanDefinitions(doc.getDocumentElement());

      -> preProcessXml(root);

       parseBeanDefinitions(root, this.delegate);  //从根节点标签开始解析

       postProcessXml(root);

      -> parseDefaultElement(ele, delegate);  //解析默认元素标签: <beans></beans>

       delegate.parseCustomElement(ele);  //解析自定义元素标签

        --> 默认标签解析

          if (delegate.nodeNameEquals(ele,"import")) {

            importBeanDefinitionResource(ele);  //处理import标签元素

          }else if (delegate.nodeNameEquals(ele, "alias")) {

            processAliasRegistration(ele);  //处理alias标签元素

          }else if (delegate.nodeNameEquals(ele,"alias")) {

              processBeanDefinition(ele, delegate);  //处理bean标签元素

          }else if (delegate.nodeNameEquals(ele,"beans")) {

              doRegisterBeanDefinitions(ele);  //递归处理beans标签元素

          }

          --->  处理import标签元素

            String location = ele.getAttribute("resource");  //获取resource属性

            location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);  //通过之前加载的系统环境变量替换字符串中的如: ${user.dir}的变量

            boolean absoluteLocation = false;

            try {

              absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); //判断location是绝对URI还是相对URI, classpath*:开头的为绝对路径

            }

            //如果是绝对URI则直接根据地址加载对应的配置文件

              getReaderContext().getReader().loadBeanDefinitions(location, actualResources);

            //如果是相对路径,则根据相对地址计算出绝对地址

              getReaderContext().getReader().loadBeanDefinitions(relativeResource);

            //解析后进行监听器激活处理

          --->   处理alias标签元素

              String name = ele.getAttribute(''name");  //获取beanName

              String alias = ele.getAttribute("alias");  //获取alias

              getReaderContext().getRegistry().registerAlias(name, alias);  //注册alias

              getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));  //别名注册后通知监听器做相应处理

          --->   处理bean标签元素

              beanDefinitionHolder是beanDefinition对象的封装类,封装了BeanDefinition,bean的名字和别名,用它来完成向IOC容器的注册, 

              得到beanDefinitionHolder就意味着beandefinition是通过BeanDefinitionParserDelegate对xml元素的信息按照spring的bean规则进行解析得到

              BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

              BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  //向ioc容器注册解析得到的beandefinition的地方

              getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  //在beandefinition向ioc容器注册完成之后,发送消息

              ---->  <bean>标签解析处理

                  String id = ele.getAttribute("id");  //解析id属性

                  String nameAttr = ele.getAttribute("name");  //解析name属性

                  AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  //对bean元素的详细解析

                  return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);  //封装为BeanDefinitionHolder返回

                -----> 对bean元素的详细解析

                  className = ele.getAttribute("class").trim();

                  parent = ele.getAttribute("parent");

                  AbstractBeanDefinition bd = createBeanDefinition(className, parent);  //创建装在bean信息的AbstractBeanDefinition对象,实际的实现是GenericBeanDefinition -> BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader()); -> GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setBeanClass(ClassUtils.forName(className, classLoader));

                  parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);  //解析bean标签的各种其他属性

                  bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));  //设置description信息

                  parseMetaElements(ele, bd);  //解析元数据

                  parseLookupOverrideSubElements(ele, bd.getMethodOverrides());  //解析lookup-method属性

                  parseReplacedMethodSubElements(ele, bd.getMethodOverrides());  //解析replaced-method属性

                  parseConstructorArgElements(ele, bd);  //解析构造函数参数

                  parsePropertyElements(ele, bd);  //解析property子元素

                  parseQualifierElements(ele, bd);  //解析qualifier子元素

                  bd.setResource(this.readerContext.getResource());

                  bd.setSource(extractSource(ele));

        --> 自定义标签解析

          String namespaceUri = getNamespaceURI(ele);  //获取对应的命名空间

 

 

          NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);  //根据命名空间找到对应的NamespaceHandlerspring, 如: 

 

          handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));  //调用自定义的NamespaceHandler进行解析

 

 

上面几步总结,  解析过程是由documentLoader完成的, 从String[] -> String -> Resource[] > Resource, 最终将resource读取成一个document文档,根据document文档的节点信息, 封装成一个个的BeanDefinition对象;

      

 

posted @ 2024-02-26 17:35  小黑与小白  阅读(39)  评论(0)    收藏  举报