概述
在前面的学习当中,我们了解了spring的资源加载策略,知道了spring如何将资源封装为Resource并且利用ResourceLoader加载Resource资源,然后解析Resource资源,将其装换为保存在spring内部的元数据BeanDefinition。前面做的所有工作都是在为IOC容器开始Bean的加载所做的准备。
IOC容器的作用如上图所示,它通过加载元数据,然后将其解析到容器内部。然后根据这些信息绑定整个系统的对象,最终 组装成一个可用的基于轻量级容器的应用系统。 要想真正得到一个完整的IOC容器,需要两步:1.容器的初始化阶段和bean的加载阶段,而现在我们学习的内容就是针对于第二个阶段。
在Bean的加载阶段开始的时候,加载Bean所需要的全部的信息已经进入到系统中了。当我们显式或者隐式地调用 BeanFactory#getBean(…) 方法的时候,就会开启Bean的加载过程。
实例代码如下:
ResourceLoader resourceLoader = new DefaultResourceLoader();// <1>
//ClassPathResource resource = new ClassPathResource("bean.xml");
ClassPathResource resource = (ClassPathResource)resourceLoader.getResource("bean.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); // <2>
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); // <3>
reader.loadBeanDefinitions(resource); // <4>
Car car = (Car)factory.getBean("car");
System.out.println(car);
为了便于梳理整个加载过程,其时序图如下:
这里的时序图只是bean加载过程当中我认为比较重要的方法,具体的看代码分析。
总体流程分析
getBean
当我们显式或者隐式掉一共getBean方法的时候,就会触发架子啊Bean阶段。
@Override
public Object getBean(String name) throws BeansException {
//doGetBean接受4个方法参数:获取bean的名字,bean的类型
//创建bean式要传递的参数,是否类型检查。
return doGetBean(name, null, null, false);
}
真正实现加载机制的是doGetBean方法
doGetBean
这个方法就是上面时序图的体现。代码如下:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
/**
* 通过name获取beanName,这里不使用name直接作为beanName有两个原因
* 1.name可能以&字符开头,表明调用者想获取FactoryBean本身,而不是FactoryBean实现类所创建的
* bean。在BeanFactory中,FactoryBean的实现类和其他的bean存储方式是一样的。区别在于名字上多了个&
* 所以要移除这个&
* 2.还是别名的问题,转换需要。
*/
//1.返回bean名称,剥离工厂使用前缀,如果那么是alias,就过去对应的映射的beanname
//如果是FactoryBean,要去除它前面的那个&
final String beanName = transformedBeanName(name);
//创建一个空的bean
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//如果这里是我们的bean,那么第一次获取肯定是空的,那么这个时候就会走else
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName +