spring 源码学习-容器初始化-1

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("application.xml")); ①
TestBean testBean = (TestBean)bf.getBean("testBean"); ②

①: spring bean 配置文件的读取

  • new ClassPathResource("application.xml") 返回一个 Resouce 的接口
    这里写图片描述
    Resource 接口抽象了Spring内部使用到的底层资源,File,Url,ClassPath等

    • 首先 定义了3个判断当前资源窗台的方法,存在性 exists() , 可读性 isReadable() , 是否处于打开状态 isOpen()
    • 获取属性 isModified(), getFilename()
    • 对应不同来源的资源有不同的实现: ByteArrayResource,DescriptiveResource,FileSystemResource,ClassRelativeContextResource,UrlResource,InputStreamResource 。
  • XmlRBeanFactory( Resource resource) 构造方法接收 resource 对象,使用XmlBeanDefinitionReader来加载Bean

    准备工作(XmlBeanDefinitionReader

    • 封装资源文件
    • 获取输入流。从Resource中获取对应的InputStream 并构造InputSource
    • 通过构造的InputSource 实例和 Resource实例调用函数 doLoadBeanDefinitions

      • 由于xml文件编码问题,第一步首先是是对资源文件进行编码处理 EncodeResource 构造出一个 EncodedResource 已编码的 Resource
      • return doLoadBeanDefinitions(inputSource, encodedResource.getResource())(核心方法) 通过InputSource 和 EncodedResource 来加载bean是读取配置文件真正的核心部分了。

        • 第一步 是通过[ inputSource,getEntityResolver(), errorHandler, validationMode, isNamespaceAware()]获取 Document 对象。(DocumentLoader

          • DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);通过 validationMode 和 namespaceAware 获得一个 DocumentBuilderFactory对象
          • DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); 通过factory,entityResolver,errorHandler 获取一个 DocumentBuilder 对象。
          • 通过 builder.parse(inputSource);得到document
        • 第二步 registerBeanDefinitions(doc, resource); 返回本次加载bean的数量

          • documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 主要关注这个方法。 方法内从doc的root节点开始遍历文档读取配置。doRegisterBeanDefinitions(root); 的源码:
            这里写图片描述
            PROFILE_ATTRIBUTE 中间部分主要在校验这个属性,xml配置中 profile 属性可以在生产环境和开发环境中配置2套不同的配置,这样方便随时切换,spring在这里是先读取的这个判断做出校验。
            preProcessXml(root);postProcessXml(root); 的代码均为空,应该是使用了模板模式,让子类可以扩展。
            parseBeanDefinitions(root, this.delegate); 的源码:
            这里写图片描述
            parseBeanDefinitions 中 会先判断 delegate.isDefaultNamespace(ele) 是否是默认命名空间(根据 element 的 BEANS_NAMESPACE_URI ),如果是就使用spring默认的读取规则,否则就使用 BeanDefinitionParserDelegate 的转换方法。2个parseDefaultElement 是完全不同的逻辑

  • BeanDefinion 是一个接口,在Spring中存在三种实现: RootBeanDefinition,ChildBeanDefinition,GenericBeanDefinition. 三种均继承自 AbstractBeanDefinition。BeanDefinition是配置文件<bean> 元素标签在容器中的内部表现形式。<bean> 中的 class, scope,lazy-init 对应 BeanDefinition中的 RootBeanDefinition是常用的实现类。GenericBeanDefinition是一站式服务类。<bean> 元素可以定义父类和子类,一般父类是 RootBeanDefinition 子类是 ChildBeanDefinition。
  • BeanDefinitionRegistry类相当于spring的bean的内存数据库,以map形式保存bean的信息

  • DefaultBeanDefinitionDocumentReader 的 parseDefaultElement 方法
    这里写图片描述
    方法对应 IMPORT_ELEMENT,ALIAS_ELEMENT, BEAN_ELEMENT, NESTED_BEANS_ELEMENT 这4种标签

BEAN_ELEMENT
这里写图片描述

  • BeanDefinitionHolder 是一个bean定义的持有对象,有private final BeanDefinition beanDefinition; 的成员和 beanName , aliases[] 别名数组 。注册bean时需要这个对象
  • delegate.parseBeanDefinitionElement(ele); 转换element 元素为 beanDefinitionHolder
    这里写图片描述

    • 获取 id 和 name 和 aliases 节点的值 ,并把id作为 beanName 的值
    • 校验 beanName 唯一性
    • AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); 获取 BeanDefinition
      这里写图片描述

      • 获取类名,父类名
      • AbstractBeanDefinition bd = createBeanDefinition(className, parent); 根据类名和父类名创建一个 BeanDefinition。具体方法: BeanDefinitionReaderUtils.createBeanDefinition(
        parentName, className, this.readerContext.getBeanClassLoader());

        方法内通过 ClassUtils.forName(className, classLoader) 获取bean的类,返回GenericBeanDefinition
      • parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); 中设置BeanDefine各类基本详细属性
      • parseMetaElements(ele, bd);
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
        parseConstructorArgElements(ele, bd);
        parsePropertyElements(ele, bd);
        parseQualifierElements(ele, bd);
        这些根据方法名都很好理解
    • 如果没有检测到 beanName 使用默认规则为此Bean 设置 BeanName

    • 最后根据获得的 bd 返回 BeanDefinitionHolder
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值