基础代码
这里不采用注解的形式进行流程分析,采用最原始的方法分析spring是如何将一个
Bean
完成解析的。
- 以下代码是一个最简单的例子。
public static void main(String[] args) {
Resource resource = new ClassPathResource("applicationContext.xml");
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
beanDefinitionReader.loadBeanDefinitions(resource);
Student student = (Student) defaultListableBeanFactory.getBean("student");
System.out.println(student.getName());
System.out.println(student.getAge());
}
<?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 -->
<bean id="student" class="com.t.spring.bean.Student">
<property name="name" value="zhangsan"/>
<property name="age" value="20"/>
</bean>
</beans>
概念介绍
粗略的介绍一下概念,以及上述代码的大致流程。
IoC(Inverse of Control)控制反转:简单的来说就是无需自己去
new
一个对象直接从工厂中获取即可。DI(Dependency Injection)依赖注入:当A依赖B,那么B也会被创建出来。
关于Spring容器管理[object Object]的过程以及加载模式
需要将bean的定义信息声明在spring的配置文件当中。
需要通过Spring抽象出的各种
Resource
来指定对应的配置文件。需要显示声明一个Spring工厂,该工厂用来掌控我们在配置文件中所声明的各种
Bean
以及Bean
之间的依赖与注入关系。需要定义一个配置信息读取器,该读取器用来读取之前所定义的bean配置文件信息。
读取器的作用是读取我们所声明的配置文件信息,并且将读取后的信息装配到之前所声明的工厂当中。
需要将读取器与工厂以及资源对象进行相应的关联处理。
工厂所管理的全部对象装配完毕,可以供客户端直接调用,获取客户端想要使用的各种bean对象。
Spring对于Bean管理的核心组件
资源抽象,例如:
ClassPathResource
。工厂,例如:
DefaultListableBeanFactory
。配置信息读取器,例如:
BeanDefinitionReader
。BeanFactory
是Spring Bean工厂最顶层的抽象。
分析代码
分析1
Resource resource = new ClassPathResource("applicationContext.xml");
大致流程,会去解析路径是否合法,并且会去添加ClassLoader
分析2
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
创建一个工厂
分析3
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
因为配置文件是Xml格式的所以,使用XmlBeanDefinitionReader
这个抽象类,需要将defaultListableBeanFactory
传入。因为解析完成后需要将一个个Bean
对象放入到工厂当中。
什么是Environment
Environment
是一个接口,代表当前程序运行的环境对两个方面进行处理处理,
profilem
和properties
profilem`决定运行的是开发环境还是生产环境
properties
是运行的各种各样的属性
总结:就是将defaultListableBeanFactory
赋值给private final BeanDefinitionRegistry registry;
然后确定ResourceLoader
和Environment
分析4
- 这一行代码应该是主要的,粗略的看它讲xml进行解析,然后放入到工厂中,然后我们就可以直接从工厂中取出对象了。
`beanDefinitionReader.loadBeanDefinitions(resource);`
图解流程
总结Spring Bean实例的组册流程
定义好Spring配置文件。
通过Resource对象将Spring配置文件进行抽象,抽象成一个具体的Resource对象(如ClassPathResource)。
定义好将要使用的Bean工厂(各种BeanFactory)。
定义好XmlBeanDefinitionReader对象,并将工厂对象作为参数传递过去,从而构建好两者之间的关联关系。
通过XmlBeanDefinitionReader对象读取之前所抽取出的Resource对象。
流程开始进行解析
针对XML文件进行各种元素以及元素属性的解析,这里面,真正的解析是通过BeanDefinitionParserDelegate对象来完成的(委托模式)
通过BeanDefinitionParserDelegate对象在解析XML文件时,又用到了模版方法设计模式(pre,process,post)。
当所有的bean标签元素都解析完毕后,开始定义一个BeanDefinition对象,该对象是一个非常重要的对象,里面容纳了一个Bean相关的所有属性。
BeanDefinition对象创建完毕后,Spring又会创建一个BeanDefinitionHolder对象来持有这个BeanDefinition对象。
BeanDefinitionHolder对象主要包括两部分内容:beanName和BeanDefiniton。
工厂会将解析出来的Bean信息存放到内部的一个ConcurrentHashMap中,该Map的键是beanName(唯一),值是BeanDefinition对象。
调用Bean解析完毕的触发动作,从而触发响应的监听器的方法来执行(使用到了观察者模式)。