01-spring对象的创建
流程图
spring的基础接口
Resource+ResourceLoader
可以看到Resoure接口下有许多的实现类,对不同的资源方法方式都有不同的加载对象
在ResourceLoader接口中使用getResource()方法可以获取到Resource,一个明显的策略模式,根据不同的地址方式返回不同的Resoure对象。
真正使用策略模式的地方在AbstractApplicationContext这个类中,ResourcePatternResolver实现了ResourceLoader接口
BeanFactory
我们可以发现BeanFactory这个接口提供了很多获取bean的方法,那既然叫工厂,最重要的是要创建bean,创建bean的方法又是在何处定义的?
BeanFactory接口下有诸多的接口以及抽象类:这里只是一小部分
在接口AutowireCapableBeanFactory中我们可以看到一个方法,至此bean工厂的核心创建功能才出现
接着又有问题出现了,不管我们是用初始的xml去配置bean,还是使用注解,spring是如何去获取这些配置信息的呢,BeanFactory以及其子接口拥有的获取bean以及创建bean的能力,那又是如何去创建的呢。我么都知道spring创建对象使用了反射,根据类的定义信息去创建出bean对象来,好下一步就是去分析,spring如何获取bean的定义信息的。
在BeanFactory接口下的实现类里有一个DefaultListableBeanFactory类可以说这个类里面存储了所有的bean定义信息,就是个档案馆
/**
* Spring's default implementation of the {@link ConfigurableListableBeanFactory}
* and {@link BeanDefinitionRegistry} interfaces: a full-fledged bean factory
* based on bean definition metadata, extensible through post-processors.
* 官方的注释是指:一个基于 bean 定义元数据的成熟 bean 工厂,可通过后处理器扩展。
* 典型用法是在访问 bean 之前首先注册所有 bean 定义(可能从 bean 定义文件中读取)。
* 因此,按名称查找 Bean 是在本地 bean 定义表中的廉价操作,对预先解析的 bean 定义元数据对象进行操作。
* <p>Typical usage is registering all bean definitions first (possibly read
* from a bean definition file), before accessing beans. Bean lookup by name
* is therefore an inexpensive operation in a local bean definition table,
* operating on pre-resolved bean definition metadata objects.
*
*/
在次类中有beanDefinitionMap这样一个map记录了根据bean名字以及bean定义信息的集合,同时为了方便获取还记录名称集合,单例集合等
我们接下来看一看BeanDefinition为何物
BeanDefinition
/**
* A BeanDefinition describes a bean instance, which has property values,
* constructor argument values, and further information supplied by
* concrete implementations.
* BeanDefinition描述了一个bean实例,里面有这个实例的属性值,构造函数参数值,以及更多的由具体实现提供的信息
* <p>This is just a minimal interface: The main intention is to allow a
* {@link BeanFactoryPostProcessor} to introspect and modify property values
* and other bean metadata.
* 这只是一个最小的接口:主要目的是允许BeanFactoryPostProcessor内省和修改属性值和其他 bean 元数据。
*/
这是啥?这就是我们心心念念的bean的定义信息啊。spring容器更具这些信息可以创建出我们想要的bean对象来了。如何来的,spring解析我们xml配置文件以及注解得出来的bean的定义信息呗。
BeanDefinitionReader
解析xml、注解等解析出来的bean的配置信息,将他们解析封装到beanDefinition中
BeanDefinitionRegistry
将前一步解析出来的beanDefinition注册进入上边说的档案馆里,至此在创建bean对象前的准备工作才算完成。
- ApplicationContext
- Aware
debug
<?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 class="com.wh.spring.bean.Person" id="person">
<property name="name" value="张三"/>
</bean>
<bean class="com.wh.spring.bean.Cat" id="cat">
<property name="name" value="猫爷"/>
</bean>
</beans>
/**
* TODO
*
* @author wanghan
* @date 2021/8/30 12:49
**/
public class MainTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person bean = context.getBean(Person.class);
Cat cat = context.getBean(Cat.class);
System.out.println(cat);
System.out.println(bean);
}
}
打入断点
在DefaultListableBeanFactory
类的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
方法里打上断点因为只用这个方法里向bean定义信息的map里放入bean定义信息。断点到后,从堆栈信息表里看之前的方法调用
堆栈信息
读取配置文件,使用类路径下的xml
去刷新容器
创建记录bean信息以及可以创建bean对象的bean工厂
刷新bean工厂
这个创建了存储的档案馆,并将其返回组合进入容器
档案馆建好后要去解析配置文件了
获取传入的配置文件集合,这里可以发现配置文件xml是可以传多个的,使用的是数组去接受
开始循环解析每个配置文件里的内容
解析得到配置文件解析出的resource
这里做了一个转换,将spring自己定义的Reource转换成了java的InputStreamSource 适配器模式,对接InputStreamSource 和 spring自己的 Resource
spring使用了第三方jar的xml解析包,去解析xml,这里是在XmlBeanDefinitionReader里操作,即实现了BeanDefinitionReader
接口的类
解析出doc对象后要去解析doc内容一个一个标签去解析
将解析出的配装到BeanDefinitionHolder
对象中
在此将BeanDefinitionHolder
中的封装好的beanDefinition传入档案馆
档案馆DefaultListableBeanFactory
中去添加bean定义信息
对于DefaultListableBeanFactory
档案馆实现了注册、存储bean定义信息等多个接口,容器对象和他是组合关系