BeanFactory的启动流程
在了解容器的原理后,我们对 BeanFactory 进行分析,这里我们选取 BeanFactory的典型实现 XmlBeanFactory
一、BeanFactory 的特点
1、BeanFactory 顾名思义,就是生产 bean 的工厂
2、读取配置文件,解析后注册的 BeanDefinition 就是bean的图纸,BeanDefinition 会被 BeanFactory 缓存起来
3、BeanFactory 实现 BeanDefinitionRegistry 接口用于对 BeanDefinition 增删改
3、可以通过 BeanFactory 工厂 getBean() 获取,工厂会根据图纸装配好 bean 实例
4、BeanFactory 默认采用延迟初始化策略(Lazy-load),geitBean() 才触发实例化
5、DefaultListableBeanFactory 是整个 bean 加载的核心部分,是 Spring 注册及加载 bean 的默认实现。
6、XmlBeanFactory 继承自 DefaultListableBeanFactory,使用了自定义的XML读取器 XmlBeanDefinitionReader ,主要用于XML配置读取 BeanDefinition。
二、附上 BeanFactory 的类图
可以了解下每个接口的含义,BeanFactory实现这些接口后获得的能力。
三、深入分析启动流程:
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
1、配置文件封装,Spring抽象Resource接口对所有资源文件进行统一处理
*2、调用XmlBeanFactory父类AbstractAutowireCapableBeanFactory构造器,忽略给定的BeanNameAware等Aware接口实现类的自动装配
3、使用XmlBeanDefinitionReader加载XML资源文件、解析注册bean
*3.1、使用EncodeResource类进行封装Resource【EncodeResource的作用?用于对资源文件的编码处理,主要逻辑体现在getReader()方法上,当设置了编码属性的时候Spring会使用相应的编码作为输入流的编码】
3.2、将Resource中的InputStream作为参数构造InputSource,org.xml.sax.InputSource类可用于XML文档的解析
3.3、加载XML文件,并得到对应的Document对象
3.3.1、获取XML的验证模式,XML有两种常用的验证模式:DTD、XSD。如果未设定验证模式,则委托XmlValidationModeDetector类自动检测验证模式。
3.3.2、委托DocumentLoader将InputSource解析为Document文档。【SAX解析XML通过创建DocumentBuilderFactory,通过factory创建DocumentBuilder,解析inputSource】【EntityResolver的作用是自实现一个寻找DTD定义的方法,以代替网络下载DTD定义。DTD定义用于对文档进行验证】
4、构造BeanDefinitionDocumentReader实例,并委托其解析并注册BeanDefinition。
4.1、首先,提取Document的root元素,作为参数,则递归调用doRegisterBeanDefinitions()进行解析(
*4.2、【对profile属性进行处理,profile使我们可以在配置文件中部署多套
4.3、Spring的XML配置有两大类Bean声明:默认、自定义;通过比对节点和Spring固定的命名空间判断类别,对不同的Bean声明类别使用不同解析逻辑。
5、解析默认标签
5.1、分别对 import、alias、bean、beans 4种标签做不同的处理
5.2、bean标签的加载
5.2.1、委托BeanDefinitionDelegate类解析元素,返回BeanDefinitionHolder实例
5.2.2、若默认标签节点下存在子节点,需在次对自定义标签进行解析
5.2.3、委托BeanDefinitionReaderUtils对解析后的BeanDefinitionHolder实例进行注册。注册分为两部分:通过beanName注册、通过别名注册
5.2.4、发布事件,通知相关监听器,该bean定义已解析注册完成
6、解析自定义标签
6.1、获取标签的命名空间,由org.w3c.dom.Node提供获取方法
6.2、提取自定义标签处理器,如果Map缓存为空,则加载“META-INF/Spring.handlers”下的Properties,解析得到处理器映射后,进行Map缓存
6.3、从handlerMapping中以命名空间为key获取对应handler处理器,如果处理器未解析,将value中的String路径转化为类,则初始化(注册自定义BeanDefinitionParser)并更新Map缓存(用初始化后的Handler对象代替String类路径)
6.4、将解析工作委托给自定义解析器进行处理,调用对应处理器的parse方法(该方法由父类NamespaceHandlerSupport提供),再调用parseInternal方法,调用自定义BeanDefinitionParser的parse,对文档节点自定义标签进行解析,并处理和执行自定义逻辑。
6.5、如parseInternal过程中返回不空,则包装BeanDefinition为Holder,并进行注册。