一、背景
我们都知道Spring可以通过xml,或者解析我们的注解,通过扫描所有资源文件,从而将所有匹配到的资源封装成为一个BeanDefinition注册到我们的BeanFactory中。
此时,Spring已经知道了所有我们想要注册到容器中的BeanDefinition,下一步就是将BeanDefinition实例化,这样才能提供出来给我们使用。
二、Spring中Bean的实例化
我们发现Spring整个加载过程都在AbstractApplicationContext.refresh()中去完成。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. 准备刷新 prepareRefresh();// Tell the subclass to refresh the internal bean factory. /* * 刷新内部BeanFactory * ClassPathXmlApplicationContext:1.新建BeanFactory,2.解析xml,3.封装成BeanDefintion对象 * AnnotationConfigApplicationContext: 获取GenericApplicationContext中的beanFactory */ ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // 为BeanFactory进行必要的准备工作 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. // 进行额外的后置处理 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. // 执行1.BeanDefinitionResgistryPostProcessor、2.BeanFactoryPostProcessor的回调 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 实例化所有实现了BeanPostProcessor接口的类并注册到容器中去 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. 国际化 initMessageSource(); // Initialize event multicaster for this context. 初始化事件类 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. 子容器自定义实现 onRefresh(); // Check for listener beans and register them. 注册事件 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. //1.bean实例化,2.ioc 3.注解支持 4.BeanPostProssor执行 5.AOP入口 finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); }
}
我们着重关注一下finishBeanFactoryInitialization方法,它是Spring实例化的入口方法。
- 获取BeanFactory中所有的beanDefinition名称
- 合并RootBeanDefinition
- 非抽象的,单例的,非懒加载的就实例化
- 是否实现了FactoryBean接口,如果是加一个&前缀调用内部的getObject,否则直接获取
- 首先尝试从缓存中获取getSingleton(beanName),(首次获取必然获取不到)接着进入创建方法
- 单例创建之前的操作:加入到正在创建的一个set集合中singletonsCurrentlyInCreation
- 调到外部的匿名类中的实例化方法,如果有值已经创建成功singletonFactory.getObject();
- 调到doCreateBean创建实例BeanWrapper
- 允许早期引用加入单例工厂直接返回这个bean的引用。addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
- 填充属性的值populateBean
- initializeBean
三、Spring容器如何解决循环依赖
什么是循环依赖
循环依赖就是循环引用,就是两个或多个 bean 相互之间的持有对方,比如 CircleA 引用 C ircleB , CircleB 引用 CircleC, CircleC 引用 CircleA,则它们最终反映为一个环。
@Component public class CircleClassA { public CircleClassA() { System.out.println("====CircleClassA===="); } }@Component public class CircleClassB { public CircleClassB() { System.out.println("====CircleClassB===="); } }
首先我们需要明确的一点是:Spring只会处理上述类型的循环依赖(单例,非构造函数注入)其它情况直接报错。
Spring在处理Bean实例化的过程中是如何解决循环依赖的呢?我们需要着重关注如下3个Map。
singletonObjects
earlySingletonObjects
singletonFactories
具体步骤如下:
CircleClassA 在实例化的时候 首先从缓存中获取不到,然后进入创建方法,接着将CircleClassA加入到singletonsCurrentlyInCreation中,并在singletonFactories加入一个getEarlyBeanReference,表示当前CircleClassA正在创建中。
当CircleClassA填充属性的值populateBean时,发现依赖了CircleClassB,触发CircleClassB的实例化。
实例化CircleClassB,首先从缓存中获取不到,然后进入创建方法,接着将CircleClassB加入到singletonsCurrentlyInCreation中,并在singletonFactories加入一个getEarlyBeanReference,表示当前CircleClassB正在创建中。
当CircleClassB填充属性的值populateBean时,发现依赖了CircleClassA,触发CircleClassA的实例化。
再次进入CircleClassA 的实例化方法,此时虽然singletonObjects中获取不到CircleClassA,但是检测到CircleClassA存在早期暴露的实例因此尝试从earlySingletonObjects中获取,首次调用获取不到从singletonFactories中获取,取到之后将CircleClassA放入earlySingletonObjects,并提供给CircleClassB填充属性的值populateBean时使用。(此时的CircleClassA只是个引用的地址,实际上并不是一个完整的CircleClassA)。
此时CircleClassB已经完成了(内部依赖的CircleClassA是个不完整的实例)并提供给CircleClassA填充属性的值populateBean时使用。CircleClassA完成了CircleClassB的注入,它变成了一个完整的实例。
又由于CircleClassB中引用了CircleClassA的一个地址。所以它也同时变成了一个完整的。
实例化完成之后删除早期引用map,并放入单例map中缓存singletonObjects。
程序员的核心竞争力其实还是技术,因此对技术还是要不断的学习,关注“IT巅峰技术” ,该公众号内容定位:中高级开发、架构师、中层管理人员等中高端岗位服务的,除了技术交流外还有很多架构思想和实战案例,作者是“《 消息中间件 RocketMQ技术内幕》 ”一书作者,同时也是“RocketMQ上海社区”联合创始人,曾就职于拼多多、德邦等公司,现任上市快递公司架构负责人,主要负责开发框架的搭建、中间件相关技术的二次开发和运维管理、混合云及基础服务平台的建设;
请关注公众号,一起探讨、学习.