概述
面向资源(XML、Properties)、面向注解定义的 Bean 是如何被解析成 BeanDefinition(Bean 的“前身”),并保存至 BeanDefinitionRegistry 注册中心里面,实际也是通过 ConcurrentHashMap 进行保存。
Spring 底层 IoC 容器 DefaultListableBeanFactory,实现了 BeanFactory 和 BeanDefinitionRegistry 接口,这个时候它处于“就绪状态”,当我们显示或者隐式地调用 getBean(...) 方法时,会触发加载 Bean 阶段,获取对应的 Bean。在该方法中,如果是单例模式会先从缓存中获取,已有则直接返回,没有则根据 BeanDefinition 开始创建这个 Bean。
主体流程:getBean doGetBean createBean doCreateBean createBeanInstance、instantiate、populateBean、initializeBean、registerDisposableBeanIfNecessary(注册销毁方法)
BeanFactory 体系结构
下来熟悉下Sprig容器BeanFactory的体系
org.springframework.beans.factory.BeanFactory,Spring IoC 容器最基础的接口,提供依赖查找单个 Bean 的功能
org.springframework.beans.factory.ListableBeanFactory,继承 BeanFactory 接口,提供依赖查找多个 Bean 的功能
org.springframework.beans.factory.HierarchicalBeanFactory,继承 BeanFactory 接口,提供获取父 BeanFactory 的功能,具有层次性
org.springframework.beans.factory.config.ConfigurableBeanFactory,继承 HierarchicalBeanFactory 接口,提供可操作内部相关组件的功能,具有可配置性
org.springframework.beans.factory.config.AutowireCapableBeanFactory,继承 BeanFactory 接口,提供可注入的功能,支持依赖注入
org.springframework.beans.factory.config.ConfigurableListableBeanFactory,继承上面所有接口,综合所有特性,还提供可提前初始化所有单例 Bean 的功能
org.springframework.beans.factory.support.DefaultListableBeanFactory,Spring 底层 IoC 容器,依赖注入的底层实现
getBean(String name) 方法,根据名称获取 Bean,当然还有许多重载方法
最终都会调用
doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) 方法
下面是编程方法获取Bean对象的方法
// 创建 BeanFactory 容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// XML 配置文件 ClassPath 路径
String location = "classpath:dependency-lookup-context.xml";
// 加载配置
int beanDefinitionsCount = reader.loadBeanDefinitions(location);
System.out.println("Bean 定义加载的数量:" + beanDefinitionsCount);
// 依赖查找
System.out.println(beanFactory.getBean("user","1","jack2"));
按照这个代码调试整理成下图的流程图
下图是关于doGetBean 方法这一层的执行逻辑。其他的核心方法后面在更新文章。
总结
可以看到这个方法加载 Bean 的过程中,会先从缓存中获取单例模式的 Bean;
不管是从缓存中获取的还是新创建的,都会进行处理,如果是 FactoryBean 类型则调用其 getObject() 获取目标对象;
BeanFactory 可能有父容器,如果当前容器找不到 BeanDefinition 则会尝试让父容器创建;
创建 Bean 的任务交由 AbstractAutowireCapableBeanFactory 去完成;
如果获取到的 Bean 不是我们想要类型,会通过类型转换机制转换成目标类型
获取 beanName
从缓存中获取单例 Bean
FactoryBean 的处理
非单例模式依赖检查
BeanFactory 层次性加载 Bean 策略
将 beanName 标记为已创建
获取 RootBeanDefinition
依赖 Bean 的处理
不同作用域的 Bean 的创建
单例模式
多例模式
其他模式
过程如下:
从当前容器获取该模式的 Scope 对象 scope,不存在则抛出异常
从 scope 中获取 beanName 对应的对象(看你的具体实现),不存在则执行原型模式的四个步骤进行创建
想要自定义一个作用域,可以实现 org.springframework.beans.factory.config.Scope 接口,并往 Spring 应用上下文注册即可 这个也是一个拓展接口
类型转换
如果入参 requiredType 不为空,并且 Bean 不是该类型,则需要进行类型转换,过程如下:
通过类型转换机制,将 Bean 转换成 requiredType 类型,对 Spring 的类型转换机制参考 org.springframework.core.convert.support.DefaultConversionService
我们也可以基于此做拓展的。
转换后的 Bean 为空则抛出异常
返回类型转换后的 Bean 对象
归纳拓展
对 BeanFactory 接口的体系结构进行了分析,得知 DefaultListableBeanFactory 是 BeanFactory 的最底层实现,也就是 Spring 的底层 IoC 容器。接着分析了 AbstractBeanFactory 的 getBean(...) 方法,当我们显示或者隐式地调用这个方法时,会触发 Bean 的加载。上面对 Bean 的加载过程进行了分析。
不同作用域的 Bean 的创建,底层都会调用 AbstractAutowireCapableBeanFactory 的 createBean(...)方法进行创建,创建 Bean 的过程涉及到 Bean 生命周期的大部分阶段,例如实例化阶段、属性赋值阶段、Aware 接口回调阶段、初始化阶段都是在这个方法中完成的。