1 IOC 源码解析
BeanDefinition:
bean的定义。里面会有beanClass、beanName、scope等属性
- beanClass:通过Class.forName生成的Class 对象
- beanName:context.getBean(“account”),acount就是beanName
- scope: 作用区分单例bean、原型bean
BeanFactory:
生产bean的工厂
可以把IOC过程分成四个状态:概念态、定义态、纯净态、成熟态。
概念态:只是通过注解或配置文件声明的bean。
定义态:spring 容器通过读取配置文件和注解,把类的定义信息装载到BeanDefinition中。
纯净态:beanFactory通过反射和BeanDefinition生成对象,还没有进行依赖注入。
成熟态:对象在进行依赖注入以及后置处理器处理后就是成熟态。
1.1 通过配置文件进行加载
public class DemoApplication {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");System.out.println(context.getBean("account"));}}
1.2 进入AnnotationConfigApplicationContext
public AnnotationConfigApplicationContext(String... basePackages) {this();//包扫描this.scan(basePackages);//容器刷新this.refresh();}
1.3 进入核心方法refresh的源码
refresh() 方法是 Spring 上下文启动的核心方法。它包含了多个步骤,这些步骤确保了 Spring 容器被正确初始化和配置。
public void refresh() throws BeansException, IllegalStateException {synchronized(this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符。this.prepareRefresh();//生成beanFactory//把通过注解或配置文件声明的bean,解析成BeanDefinition,注册到BeanFactory中。ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();//设置bean的类加载器,添加几个BeanPostProcessor,手动注册几个特殊的 beanthis.prepareBeanFactory(beanFactory);try {//具体的子类可以在这步的时候添加一些特殊的BeanFactoryPostProcessor的实现类//可以对BeanFactory进行一些处理和BeanPostProcessor相似this.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");//调用BeanFactoryPostProcessor各个实现类的postProcessBeanFactory(factory)方法this.invokeBeanFactoryPostProcessors(beanFactory);//注册BeanPostProcessor的实现类//此接口两个方法:postProcessBeforeInitialization和postProcessAfterInitialization//两个方法分别在Bean初始化之前和初始化之后得到执行,这里仅仅是注册。this.registerBeanPostProcessors(beanFactory);beanPostProcess.end();//初始化 MessageSource,用于国际化支持。this.initMessageSource();//初始化事件发布器,用于事件发布和监听。this.initApplicationEventMulticaster();//模板方法,允许子类在容器刷新时进行特定的初始化操作。this.onRefresh();//注册事件监听器。this.registerListeners();//重点!!!//完成BeanFactory的初始化,包括实例化所有的非懒加载的单例bean。this.finishBeanFactoryInitialization(beanFactory);//完成刷新的最后步骤,比如发布上下文刷新事件。this.finishRefresh();} catch (BeansException var10) {BeansException ex = var10;if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);}this.destroyBeans();this.cancelRefresh(ex);throw ex;} finally {this.resetCommonCaches();contextRefresh.end();}}}
(1)【1.准备刷新 】prepareRefresh();
主要是一些准备工作设置其启动日期和活动标志以及执行一些属性的初始化。(不是很重要的方法)
(2)【2.初始化 BeanFactory 】obtainFreshBeanFactory();(重点方法)
<1>如果有旧的BeanFactory就删除并创建新的BeanFactory<2>解析所有的Spring配置文件,将配置文件中定义的bean封装成BeanDefinition,加载到BeanFactory中(这里只注册,不会进行Bean的实例化)
(3)【3.bean工厂前置操作】prepareBeanFactory(beanFactory);
配置 beanFactory 的标准上下文特征,例如上下文的 ClassLoader、后置处理器等。
(4)【4.bean工厂后置操作】postProcessBeanFactory(beanFactory);
空方法,如果子类需要,自己去实现
(5)【5.调用bean工厂后置处理器】invokeBeanFactoryPostProcessors(beanFactory);
实例化和调用所有BeanFactoryPostProcessor,完成类的扫描、解析和注册BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。
(6)【6.注册bean后置处理器】registerBeanPostProcessors(beanFactory);
将所有实现了 BeanPostProcessor 接口的类注册到 BeanFactory 中。
(7)【7.初始化消息源】initMessageSource();
初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
(8)【8.初始化事件广播器】initApplicationEventMulticaster();
初始化应用的事件广播器 ApplicationEventMulticaster。
(9)【9.刷新:拓展方法】onRefresh();
空方法,模板设计模式;子类重写该方法并在容器刷新的时候自定义逻辑;例:springBoot在onRefresh() 完成内置Tomcat的创建及启动
(10)【10.注册监听器】registerListeners();
向事件分发器注册硬编码设置的applicationListener,向事件分发器注册一个IOC中的事件监听器(并不实例化)
(11)【11.实例化所有非懒加载的单例bean】finishBeanFactoryInitialization(beanFactory);
是整个Spring IoC核心中的核心
(12)【12.结束refresh操作】finishRefresh();
发布事件,ApplicationContext 初始化完成
1.4 核心方法源码解析
1.4.1 obtainFreshBeanFactory
这一步上面简单介绍过了,作用是把配置文件解析成一个个BeanBeanDefinition
,并且注册到BeanFactory
中,源码:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {this.refreshBeanFactory();return this.getBeanFactory();}
我们进入refreshBeanFactory()方法
@Override
protected final void refreshBeanFactory() throws BeansException {//如果存在旧的BeanFactory就删除if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {//创建新的BeanFactoryDefaultListableBeanFactory beanFactory = createBeanFactory();//序列化beanFactory.setSerializationId(getId());//是否允许 Bean 覆盖、是否允许循环引用customizeBeanFactory(beanFactory);//根据配置,加载各个Bean,然后放到 BeanFactory 中loadBeanDefinitions(beanFactory);synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}
}
这个方法的作用是关闭旧的 BeanFactory (如果有),创建新的 BeanFactory,加载 Bean 定义、注册 Bean 等。
1.4.2 实例化所有非懒加载的单例bean
finishBeanFactoryInitialization(beanFactory)
在这个方法中,我们主要做了以下操作:
(1)将之前解析的 BeanDefinition 进一步处理,将有父 BeanDefinition 的进行合并,获得MergedBeanDefinition
(2)尝试从缓存获取 bean 实例
(3)处理特殊的 bean —— FactoryBean 的创建
(4)创建 bean 实例
(5)循环引用的处理
(6)bean 实例属性填充
(7)bean 实例的初始化
(8)BeanPostProcessor 的各种扩展应用
这个方法解析的结束,也标志着Spring IoC重要内容基本都已经解析完毕
finishBeanFactoryInitialization(beanFactory)点进去看源码
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// 5.实例化所有剩余(非懒加载)单例对象beanFactory.preInstantiateSingletons();
}
reInstantiateSingletons();点进去看源码
@Override
public void preInstantiateSingletons() throws BeansException {List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//判断beanName对应的bean是否为FactoryBeanif (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {final FactoryBean<?> factory = (FactoryBean<?>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {//如果希望急切的初始化,则通过beanName获取bean实例getBean(beanName);}}}else {//如果beanName对应的bean不是FactoryBean,只是普通Bean,通过beanName获取bean实例getBean(beanName);}}}//遍历beanNames,触发所有SmartInitializingSingleton的后初始化回调for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}}}
}
getBean();点进去看源码
@Override
public Object getBean(String name) throws BeansException {// 获取name对应的bean实例,如果不存在,则创建一个return doGetBean(name, null, null, false);
}
doGetBean();点进去看源码
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {// 1.解析beanName,主要是解析别名、去掉FactoryBean的前缀“&” final String beanName = transformedBeanName(name);Object bean;// 2.尝试从缓存中获取beanName对应的实例Object sharedInstance = getSingleton(beanName);// 3.如果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 + "'");}}// 3.1 返回beanName对应的实例对象(主要用于FactoryBean的特殊处理,普通Bean会直接返回sharedInstance本身)bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// 4.scope为prototype的循环依赖校验:如果beanName已经正在创建Bean实例中,而此时我们又要再一次创建beanName的实例,则代表出现了循环依赖,需要抛出异常。if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// 5.获取parentBeanFactoryBeanFactory parentBeanFactory = getParentBeanFactory();// 5.1 如果parentBeanFactory存在,并且beanName在当前BeanFactory不存在Bean定义,则尝试从parentBeanFactory中获取bean实例if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// 5.2 将别名解析成真正的beanNameString nameToLookup = originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}// 5.3 尝试在parentBeanFactory中获取bean对象实例else if (args != null) {// Delegation to parent with explicit args.return (T) parentBeanFactory.getBean(nameToLookup, args);}else {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);}}// 6.如果不是仅仅做类型检测,而是创建bean实例,这里要将beanName放到alreadyCreated缓存if (!typeCheckOnly) {markBeanAsCreated(beanName);}try {// 7.根据beanName重新获取MergedBeanDefinition(步骤6将MergedBeanDefinition删除了,这边获取一个新的)final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// 8.拿到当前bean依赖的bean名称集合,在实例化自己之前,需要先实例化自己依赖的beanString[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {// 8.2 检查dep是否依赖于beanName,即检查是否存在循环依赖if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}// 8.4 将dep和beanName的依赖关系注册到缓存中registerDependentBean(dep, beanName);try {// 8.5 获取dep对应的bean实例,如果dep还没有创建bean实例,则创建dep的bean实例getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// 9.针对不同的scope进行bean的创建if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {// 9.1.1 创建Bean实例return createBean(beanName, mbd, args);}catch (BeansException ex) {destroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}else if (mbd.isPrototype()) {// 9.2 scope为prototype的bean创建Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}// 10.返回创建出来的bean实例对象return (T) bean;
}
getSingleton(beanName); 点进去看源码
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1.从单例对象缓存中获取beanName对应的单例对象Object singletonObject = this.singletonObjects.get(beanName);// 2.如果单例对象缓存中没有,并且该beanName对应的单例bean正在创建中if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 3.加锁进行操作synchronized (this.singletonObjects) {// 4.从早期单例对象缓存中获取单例对象(之所称成为早期单例对象,是因为earlySingletonObjects里// 的对象的都是通过提前曝光的ObjectFactory创建出来的,还未进行属性填充等操作)singletonObject = this.earlySingletonObjects.get(beanName);// 5.如果在早期单例对象缓存中也没有,并且允许创建早期单例对象引用if (singletonObject == null && allowEarlyReference) {// 6.从单例工厂缓存中获取beanName的单例工厂ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 7.如果存在单例对象工厂,则通过工厂创建一个单例对象singletonObject = singletonFactory.getObject();// 8.将通过单例对象工厂创建的单例对象,放到早期单例对象缓存中this.earlySingletonObjects.put(beanName, singletonObject);// 9.移除该beanName对应的单例对象工厂,因为该单例工厂已经创建了一个实例对象,并且放到earlySingletonObjects缓存了,// 因此,后续获取beanName的单例对象,可以通过earlySingletonObjects缓存拿到,不需要在用到该单例工厂this.singletonFactories.remove(beanName);}}}}// 10.返回单例对象return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
public boolean isSingletonCurrentlyInCreation(String beanName) {return this.singletonsCurrentlyInCreation.contains(beanName);
}
这段代码很重要,在正常情况下,该代码很普通,只是正常的检查下我们要拿的 bean 实例是否存在于缓存中,如果有就返回缓存中的 bean 实例,否则就返回 null。
这段代码之所以重要,是因为该段代码是 Spring 解决循环引用的核心代码。解决循环引用逻辑:使用构造函数创建一个 “不完整” 的 bean 实例(之所以说不完整,是因为此时该bean 实例还未初始化),并且提前曝光该 bean 实例的 ObjectFactory(提前曝光就是将
ObjectFactory 放到 singletonFactories 缓存),通过 ObjectFactory 我们可以拿到该 bean 实例的引用,如果出现循环引用,我们可以通过缓存中的 ObjectFactory 来拿到 bean 实例,从而避免出现循环引用导致的死循环。这边通过缓存中的 ObjectFactory 拿到的 bean 实例虽然拿到的是 “不完整” 的bean 实例,但是由于是单例,所以后续初始化完成后,该 bean 实例的引用地址并不会变,所以最终我们看到的还是完整 bean 实例。
另外这个代码块中引进了4个重要缓存:
(1)singletonObjects 缓存:beanName -> 单例 bean 对象。
(2)earlySingletonObjects 缓存:beanName -> 单例 bean 对象,该缓存存放的是早期单例 bean 对象,可以理解成还未进行属性填充、初始化。
(3)singletonFactories 缓存:beanName -> ObjectFactory。
【singletonObjects、earlySingletonObjects、singletonFactories 在这边构成了一个类似于 “一、二、三级缓存” 的概念】
(4)singletonsCurrentlyInCreation 缓存:当前正在创建单例 bean 对象的 beanName 集合。
createBean(beanName, mbd, args);点进去看源码
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {...try {//创建Bean实例(真正创建Bean的方法)Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isDebugEnabled()) {logger.debug("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}...
}
doCreateBean(beanName, mbdToUse, args);点进去看源码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {......Object exposedObject = bean;try {//对bean进行属性填充populateBean(beanName, mbd, instanceWrapper);//对bean进行初始化,方法中激活了AwareexposedObject = initializeBean(beanName, exposedObject, mbd);}......//完成创建并返回return exposedObject;
}
1.5 IOC流程图
2 Spring的循环依赖
2.1 三级缓存
三级缓存:
singletonObjects:一级缓存
主要存放的是已经完成实例化、属性填充和初始化所有步骤的单例 Bean 实例,这样的 Bean 能够直接提供给用户使用,我们称之为终态 Bean 或叫成熟 Bean。
earlySingletonObjects:二级缓存
主要存放的已经完成初始化,但属性还没自动赋值的 Bean,这些 Bean 还不能提供用户使用,只是用于提前暴露的 Bean 实例,我们把这样的 Bean 称之为临时 Bean 或早期的 Bean(半成品 Bean)。
singletonFactories:三级缓存
存放的是 ObjectFactory 的匿名内部类实例,调用 ObjectFactory.getObject() 最终会调用 getEarlyBeanReference 方法,该方法可以获取提前暴露的单例 Bean 引用。
2.1 流程分析
Spring 通过三级缓存解决了循环依赖,其中,一级缓存为单例池(singletonObjects),二级缓存为早期曝光对象 earlySingletonObjects,三级缓存为早期曝光对象工厂(singletonFactories)。
当 A、B 两个类发生循环引用时,在 A 完成实例化后,就使用实例化后的对象去创建一个对象工厂,并添加到三级缓存中,如果 A 被 AOP 代理,那么,通过这个工厂获取到的就是 A 代理后的对象,如果 A 没有被 AOP 代理,那么,这个工厂获取到的就是 A 实例化的对象。
当 A 进行属性注入时,会去创建 B,同时,B 又依赖了 A,所以,创建 B 的同时又会去调用 getBean(a) 来获取需要的依赖,此时的 getBean(a) 会从缓存中获取,第一步,先获取到三级缓存中的工厂;第二步,调用对象工工厂的getObject方法来获取到对应的对象,得到这个对象后将其注入到 B 中。紧接着 B 会走完它的生命周期流程,包括初始化、后置处理器等。当 B 创建完后,会将 B 再注入到 A 中,此时, A 再完成它的整个生命周期。
通过上述流程,可以看出 bean 都是需要先可以被实例化才可以的,所以,这也就是为什么构造器依赖可能会失败的原因。
例如,Bean A 的构造器依赖 B,而实例化 A 需要先调用 A 的构造函数,发现依赖 B,那么,需要再去初始化 B,但是,B 也依赖 A,不管 B 是通过构造器注入还是 setter 注入,此时,由于 A 没有被实例化,没有放入三级缓存,所以, B 无法被初始化,所以,spring 会直接报错。反之,如果 A 通过 setter 注入的话,那么,则可以通过构造函数先实例化,放入缓存,然后再填充属性,这样的话不管 B 是通过 setter 还是构造器注入 A,都能在缓存中获取到,于是可以初始化。
2.3 循环依赖的经典面试题
(1)【Spring 为何需要三级缓存解决循环依赖,而不是二级缓存?】
答:只要两个缓存确实可以做到解决循环依赖的问题,但是有一个前提这个bean没被AOP进行切面代理,如果这个bean被AOP进行了切面代理,那么只使用两个缓存是无法解决问题。
(2)【三级缓存中为什么要添加 ObjectFactory 对象,而不是直接保存实例对象?】
答:假如想对添加到三级缓存中的实例对象进行增强,直接用实例对象是行不通的。
(3)【构造器注入注入的循环依赖为什么无法解决?】
答:因为我们要先用构造函数创建一个 “不完整” 的 bean 实例,如果构造器出现循环依赖,我们连不完整的 bean 实例都构建不出来。