Spring 的核心就是 Bean,围绕这 Bean 这个概念衍生出来 IOC(控制反转),AOP(面向切面编程),该系列文章主要分析 IOC 源码;
IOC(控制反转):意思就是将我们平常编程中人为创建对象和管理对象的这一系列复杂关系,交给 Spring 容器去做
@Test public void t5() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring_1.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); userService.queryUser("long"); } 复制代码
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userService" class="com.example.ana.service.impl.UserServiceImpl" /> </beans> 复制代码
根据之前保存的 configLocations 通过 ResourcePatternResolver(ResourceLoader 的子类) 进行解析返回 Resource[],以为这里我们只有一个配置文件 spring_1.xml 所以返回数组只有一个值,Resource 代表一个资源,它描述了一个文件的相关信息
根据 Resource 获取其 InputStream,其实就是 resource.getFile().getInputstream(),然后根据 InputStream 创建 InputSource
然后调用 DefaultDocumentLoader 的 loadDocument(InputSource inputSource, EntityResolver entityResolver, ...) 方法
创建 DocumentBuilder
调用 parse(InputSource is)
最终调用 DomParser 的 parse(InputSource inputSource) 方法,将其解析为 Document
其实总结下来就一句话,根据 configLocations 对应的文件解析为 Resource,然后通过 Resource 获取到文件输入流,最后通过 DomParser 将输入流进行解析为 Document
Document 是文档的根节点,他的实现类,包含了 xml 或者 html 等文档各个节点和命名空间的数据,比如说它其中的 Element 的 node 属性就能包含 <bean id="xxx" class="xxx" />
这样一个节点数据,能够获取到它的 id、class 等,通过这个 Document 的信息就能比较方便的创建 BeanDefinition 了
http://www.springframework.org/schema/beans
这样的命名空间,那么就 BeanDefinitionParserDelegate 这个委派器解析 Element 元素将其解析后返回 BeanDefinitionHolder,解析流程不复杂大体就是通过 Element 获取 bean 元素的 id,class,别名等信息来创建 BeanDefinitionHolder, new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray)
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
// 主要逻辑 BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition != null) { this.beanDefinitionMap.put(beanName, beanDefinition); } 复制代码
spring 首先将配置文件解析为 Resource,然后根据 Resouce 获取其输入流信息解析生成 Document 通过该 Document 获取到的 Element 包含了定义的所有节点信息,然后通过 Element 获取所有的 Bean 结点遍历依次解析,解析就是通过这些结点获取 bean 定义的 id、class、alias 等信息,根据这些信息来创建 BeanDefinition,最后将 BeanDefinition 放入 DefaultListableBeanFactory 的 BeanDefinitionMap 中同时保存一份 beanDefinitionNames