Spring IOC源码浅读

一、简述

关于spring的介绍很多,它已经发展成了一个很大的家族了,然而它最原始并且最核心的功能是它的IOC/DI功能,用来帮助我们管理Java对象的,任何项目都可以从spring ioc中受益。我阅读了一下spring ioc相关源码,并记录在这篇文章中。

二、BeanFactory

BeanFactory,顾名思义,就是负责生产Bean并且管理Bean的一个Factory,IOC的核心主要就体现在这个类上。先看下它的类图,继承体系十分庞大。如果没有阅读过spring源码,初次看这张图是比较复杂的,但是读完源码之后,回过头再来看这张图,会觉得十分清晰。各个接口,各个类之间分工明确,各司其职,功能丰富,且具扩展性。

在这里插入图片描述
先对上图做个简介。
BeanFactory
BeanFactory接口是IOC的核心接口,提供获取Bean的基本方法。常说的spring容器,底层就是BeanFactory。
ListableBeanFactory
ListableBeanFactory是BeanFactory的子接口,在原有的功能基础上提供更加丰富的Bean操作,主要是枚举满足条件的Bean。例如通过注解获取一批Bean,通过类型获取一批Bean等。
AutowireCapableBeanFactory
AutowireCapableBeanFactory是BeanFactory的子接口,它主要是实现了自动装配Bean的功能。
HierarchicalBeanFactory
HierarchicalBeanFactory是BeanFactory的子接口,它主要是提供了层级的概念,一个BeanFactory可以有一个父BeanFactory。不同的两个容器可以连接起来。
SingletonBeanRegistry
提供单例对象的注册与获取,就是管理单例对象的,spring中的单例对象会统一在这里管理。
ConfigurableBeanFactory
可配置的BeanFactory,提供容器元数据的获取和设置,比如ClassLoader,BeanPostProcessor。
ConfigurableListableBeanFactory
这个接口继承子BeanFactory的三个子接口,功能大而全。
AliasRegistry
提供别名注册的功能。对类的名称和别名做一个映射。这样就可以通过别名来get一个Bean。
BeanDefinitionRegistry
BeanDefinition相当于Bean的元数据,通过它可以知道如何创建一个Bean。在容器启动时,会将需要管理的bean扫描成BeanDefinition,并注册到BeanDefinitionRegistry中。后续在getBean时,会通过名称来查找BeanDefinition,并据此创建Bean。
AbstractBeanFactory
BeanFactory的抽象实现,提供了getBean的核心逻辑,真正创建Bean的逻辑由子类实现。所有的BeanFactory实现都会继承它。
AbstractAutowireCapableBeanFactory
继承自AbstractBeanFactory,实现了创建Bean的核心逻辑。
DefaultListableBeanFactory
继承自AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory,是个功能丰富的BeanFactory。

三、getBean流程

AbstractBeanFactory的getBean方法是IOC功能的核心。接下来分析其主要流程,择其关键步骤进行分析。

1.getSignton

在这里插入图片描述
在这里插入图片描述

第一个关键步骤是getSignton方法,它的逻辑是从缓存中获取单例对象,这里就是常说的spring三级缓存。
singletonObjects是一级缓存,装已经实例化并且属性填充完成的单例对象;
earlySingletonObjects是二级缓存,装已经实例化但是属性填充未完成的单例对象,earlySingletonObjects的对象来源于三级缓存,从三级缓存中获取到对象之后就放在二级缓存中,也就是说同一个bean在三级缓存中最多get一次;
singletonFactories是三级缓存,里面存放的是ObjectFactory,通过ObjectFactory可以拿到已实例化但未完成属性注入的bean,ObjectFactory的getObject方法不一定是返回bean本身,在后面可以看到,getObject中有可能对bean进行了特定操作的,比如对其进行代理,如果从三级缓存中get多次,那么返回的bean就会被多次操作,这显然是不合理的,因此在getObjecct之后需要把bean放到二级缓存中,可以看到这个逻辑是加了锁的,对于同一个bean只会getObject一次。
这三级缓存是用来解决循环依赖的,后面走完全程再回头来体会三级缓存是如何工作的。

2.getObjectForBeanInstance

在这里插入图片描述
在这里插入图片描述
如果从getSingleton中获取到了对象,那么继续调用这个方法。这个方法是用来处理FactoryBean的,如果一个Bean是FactoryBean,则最终会调用FactoryBean的getObject方法,返回的是getObject返回的Bean。在一些场景下,我们创建一个Bean可能需要经过比较复杂的步骤,并不是直接new出来就可以了,这时就可以用FactoryBean来实现,比如Myabatis创建Mapper的代理对象就是通过MapperFactoryBean来实现的。如果我们想要获取FactoryBean本身,那么在beanName前面加上“&”就可以啦。

3.从父容器中获取

如果上面的getSingleton返回空,那么就会走这里的逻辑。如果当前BeanFactory有父BeanFactory,那么从父BeanFactory中获取。为什么会有父容器呢?在项目中,可能有多个容器,比如springmvc的,service的,在实际使用的时候controller会依赖service,需要容器互通,通过父容器这个机制将他们连接起来。
在这里插入图片描述

4.处理弱依赖

一个bean将另一个bean作为成员变量,这是强依赖。如果我们需要在实例化某个bean时,需要保证另一个bean已经被实例化,那么可以用depend-on这个属性来声明它所依赖的bean,那么在这里就会优先处理所依赖的bean。如果这里出现循环依赖是没法自动处理的,必须人为解决。
在这里插入图片描述

5.getSington

这个getSington是一个重载的方法,并不是上面提到的那个getSingleton。这里是创建bean的入口。最重要的一行代码就是singletonFactory.getObject(),通过这个Factory来获得一个实例,在这个逻辑的前后还有一些重要操作。在创建前,会执行beforeSingletonCreation,将beanName放到singletonsCurrentlyInCreation中,标识该bean在创建中。在创建后,执行afterSingletonCreation,将beanName从singletonsCurrentlyInCreation中移除。并且执行addSingleton,将bean放到一级缓存中,把二三级缓存中该bean的相关缓存移除。所以在创建Bean的前后是做了特定逻辑的。
在这里插入图片描述

在这里插入图片描述

接下来继续看创建Bean的核心逻辑,也就是OjbectFactory的getObject方法,它的核心逻辑在createBean中,它是一个抽象方法,实现在AbstractAutowireCapableBeanFactory类中,下面继续分析这个方法。
在这里插入图片描述

6.createBean

这里的主要逻辑有两个。
一是resolveBeforeInstantiation,其作用是调用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法,如果该方法返回值不为空,则直接返回该对象,从而中断实例化过程。二是doCreateBean,这个方法是用来真正创建Bean的。

7.doCreateBean

1).createBeanInstance,该方法返回一个实例,通过源码跟踪,最终会看到是通过反射,调用Constructor的newInstance实例化对象的。
2).addSingletonFactory,将刚创建好的对象放到ObjectFactory中,再将ObjectFactory放到三级缓存中。
在这里插入图片描述
在这里插入图片描述
3).populateBean,进行属性注入,顺着调用链路跟踪,populateBean -> applyPropertyValues -> valueResolver.resolveValueIfNecessary -> resolveReference 。如果该bean依赖了另一个bean,则会走到如下逻辑,最终又从容器中获取这个被依赖的bean,顺着依赖关系,这里相当于递归调用了。
在这里插入图片描述
4).initializeBean,进行Bean的初始化,此时,Bean已经完成了实例化,并且进行了属性注入。这里将对Bean做一些初始化工作。
第一、invokeAwareMethods,如果Bean实现了Aware接口,对这个Bean注入对应的对象,其实ApplicationContextAwareProcessor也是在做这件事情。
第二、调用BeanPostProcessor的postProcessBeforeInitialization方法,为初始化做准备,比如ApplicationContextAwareProcessor,给Bean设置好相应的对象。
第三、invokeInitMethods,进行初始化。如果这个Bean实现了InitializingBean接口,则调用其afterPropertiesSet方法,在其他框架与spring整合的过程中,经常能看到某些Bean实现这个接口来进行初始化。接着,如果Bean有注册init-method,则通过反射调用它。
第四、调用BeanPostProcessor的postProcessAfterInitialization方法。
BeanPostProcessor是spring提供的扩展接口,在bean初始化前后切入。
5).registerDisposableBeanIfNecessary,如果该Bean实现了DisposableBean接口,或者注册了destroyMethod,或者有DestructionAwareBeanPostProcessor支持该Bean的destruction,则标记这个将这个Bean加入到disposableBeans中,当spring容器close的时候会对集合里面的bean处理,调用其destroy方法。

到此位置getBean整个过程的核心逻辑基本讲完了,在这里粗粒的总结一下,如下图所示。
在这里插入图片描述

四、循环依赖

getter依赖

spring中有三种循环依赖,先讲第一种,也是最常见的一种,成员变量的依赖。在getBean流程中提到了三级缓存,在这里来详细分析一下spring是如何解决的。
假设A类中有个B类成员,B类有个A类成员,他们都是单例,这就形成了一个循环依赖。这时候我们来getBean(A),首次调用,缓存中必然没有A,所以会真正的创建A。在doCreateBean中有个核心逻辑–addSingletonFactory,当一个对象被实例化之后,立刻将其封装成一个ObjectFactory,并添加到三级缓存singletonFactories中。所以,A会被封装成ObjectFactory,并放在三级缓存中singletonFactories。接下来会进行A的属性填充,发现它依赖了B,则getBean(B),B也是第一次get,所以会真正的创建它。同理在实例化之后将B放到三级缓存中。接下来进行B的属性填充,发现B依赖了A,则调用getBean(A),这时候关键步骤就来了,逻辑走进getSingleton方法,一级缓存中,没有,二级缓存,没有,三级缓存,有,取之,并放到二级缓存中,getBean(A)返回,B的属性填充结束,忽略其它中间步骤,getBean(B)也返回了,最外层第一次调用getBean(A)的属性填充结束,拿到了B的引用,getBean(A)也成功返回。
可以看到其实核心思想就是Bean实例化后立刻暴露自己的引用,即使自己还没有完全初始化完成,完全不影响它被别的Bean所引用。其实,用简单的代码就可以表达它的意思。

A a = new A();
B b = new B();
a.b = b;
b.a = a;

看到没,核心思想就是先把Bean创建出来,然后在处理之间的引用关系。其实如果仅仅是为了解决循环依赖,二级缓存就足够了。那为啥需要三级缓存呢?回顾一下doCreateBean中,往三级缓存里面放的是ObjectFactory
在这里插入图片描述
看下它的实现
在这里插入图片描述
在调用getOject时,会对创建出来的Bean做处理,具体做了啥处理得看SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference的逻辑,这个方法也是spring提供的扩展方法。所以,如果多次调用了getObject方法,那么Bean就会被多次处理,这显然是不合理的。所以从三级缓存中取出objectFactory,拿到Bean之后,要放到二级缓存。循环依赖这个得细品,拿两个例子,跟着走几遍,再品,就明白了。

构造器依赖

如果是构造方法上有参数,并且形成了循环依赖,这种循环依赖是没法自动解除了,spring会抛出异常,需要手动解决。

A a = new A(new B());
B b = new B(new A());

这种情况,都没法完成实例化,在创建A时需要创建B,创建B时需要创建A,构造方法没法返回,死循环下去了。当然,上面这段代码肯定没问题,它都不是单例的了,如果是单例构造器依赖,这代码都写不出来。

depend-on依赖

关于depend-on的作用在前面讲了。depend-on是非成员变量的弱依赖关系,这种循环依赖也是没办法自动解决的,必须要手动调整两者的依赖关系。
总结,其实,循环依赖能否自动解决,手写一下代码就知道了,能够把代码写出来的,就能解决,比如getter依赖,像构造器依赖和depend-on依赖,代码根本就写不出来,自然是不可能解决的。

五、ApplicationContext

BeanFactory实现了IOC的核心功能,ApplicationContext是对BeanFactory的增强和补充。ApplicationContext代表了一个应用上下文,通过它可以管理Bean(内部有一个BeanFactory的实例),可以加载资源(继承自DefaultResourceLoader),可以进行事件的发布订阅(实现ApplicationEventPublisher接口),扩充更多的Aware接口等。在项目中,几乎不直接使用BeanFactory,而是使用功能更为强大的ApplicationContext。
ApplicationContext的核心逻辑在AbstractApplicationContext的refresh方法中,任何ApplicationContext对象在实例化时都会执行refresh方法,接下来来看看其核心逻辑。

1.prepareRefresh()

刷新容器前的准备,主要是获取Environment。

2.obtainFreshBeanFactory()

主要有两个方法,refreshBeanFactory(),destroy原来的bean,创建BeanFactory实例,并加载spring配置文件;getBeanFactory(),返回创建的beanFactory。obtainFreshBeanFactory的主要作用就是创建beanFactory,并解析配置文件,然后返回这个beanFactory。

3.prepareBeanFactory

使用BeanFactory前的准备,给beanFactory设置一些属性。例如,设置类加载器,添加ignoreDependencyInterface,注册BeanPostProcessor,比如ApplicationListenerDetector(自动注册beanFactory中的事件监听器),ApplicationContextAwareProcessor(处理Aware接口)。

4.postProcessBeanFactory

默认为空方法,提供给子类的扩展方法。

5.invokeBeanFactoryPostProcessors

invoke BeanFactoryPostProcessor,扫描BeanFactory中的BeanFactoryPostProcessor,并调用其postProcessBeanFactory方法,包括对其子接口BeanDefinitionRegistryPostProcessor接口方法的调用。可见BeanFactoryPostProcessor的调用在BeanFactory创建后,Bean进行实例化之前,这时可以做很多事情。BeanFactoryPostProcessor的经典应用之一就是占位符的解析,PropertyPlaceholderConfigurer就是一个BeanFactoryPostProcessor,其postProcessBeanFactory的逻辑就是扫描ConfigurableListableBeanFactory中所有的BeanDefinition,然后遍历BeanDefinition的所有属性,进行占位符的解析替换。
在这里插入图片描述

6.registerBeanPostProcessors

注册一个BeanPostProcessor,我们得手动执行beanFactory.addBeanPostProcessor(),而registerBeanPostProcessors会帮我们扫描beanFactory中的bean,如果它是一个BeanPostProcessor,则自动帮我们注册到BeanFactory中。

7.initMessageSource

初始化MessageSource

8.initApplicationEventMulticaster

初始化ApplicationEventMulticaster,如果beanFactory中没有ApplicationEventMulticaster,则创建一个默认的事件发布者SimpleApplicationEventMulticaster。

9.onRefresh

默认空方法,留给子类扩展。

10.registerListeners

将ApplicationListener的beanName注册到ApplicationEventMulticaster中。

11.finishBeanFactoryInitialization

即将结束refresh过程,这一步比较重要的逻辑就是提前初始化Bean,对所有的Bean挨个调用getBean方法,提前将他们实例化。

12.finishRefresh

最后一步,结束refresh。初始化LifecycleProcessor,如果beanFactory中没有,则创建默认的DefaultLifecycleProcessor;调用LifecycleProcessor的onRefresh,开始Lifecycle的生命周期;发布ContextRefreshedEvent事件,如果需要在容器初始化后做一些自定义操作的,可以监听这个事件。向LiveBeansView中注册当前ApplicationContext。

到此为止,整个容器的启动过程结束。总的来讲,还是很清晰的,先做容器刷新前的环境准备,然后创建核心实例BeanFactory并加载配置文件,接下来对BeanFactory做一些配置,再处理BeanFactoryPostProcessor,注册BeanPostProcessor,初始化容器事件发布器,提前实例化Bean,主要就是这些操作。

六、spring提供的扩展

spring是一个轻量级的,高扩展性的容器框架,从getBean和refresh两个核心方法来看,主要有两个扩展接口,spring本身的很多扩展功能,包括与其他框架的整合,也都是基于这两个接口去实现的,下面就简单分析下这两个扩展接口。

BeanFactoryPostProcessor

首先得清楚BeanFactoryPostProcessor的调用时机,在上面的refresh中讲到过,当BeanFactory创建后,就会调用BeanFactoryPostProcessor的接口方法,此时配置文件加载完毕,但还没有任何Bean被实例化,BeanFactoryPostProcessor允许你拿到容器中的所有BeanDefinition,并且可以修改他们,比如PropertyPlaceholderConfigurer,占位符的解析,它就是在Bean实例化之前去遍历所有的BeanDifnition,并且解析它们的属性值。

BeanFactoryPostProcessor有一个子接口BeanDefinitionRegistryPostProcessor,在处理BeanFactoryPostProcessor时,会先处理BeanDefinitionRegistryPostProcessor。BeanDefinitionRegistryPostProcessor允许你向容器中注册更多的BeanDifinition,它是BeanFactoryPostProcessor功能的增强。比如ConfigurationClassPostProcessor,它就是在这个时机来进行@ComponentSan、@Configuration注解的处理,向容器中注册扫描的Bean。

BeanPostProcessor

BeanPostProcessor是在doCreateBean方法中执行的,回想一下上面的doCreateBean流程,在实例化对象后,在调用初始化方法前后会invoke BeanPostProcessor的接口方法,这时候Bean仅仅被创建出来了,可感知Bean的初始化,可以在这个时候对Bean做自定义逻辑。InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口,可感知Bean的实例化。SmartInstantiationAwareBeanPostProcessor是InstantiationAwareBeanPostProcessor的子接口,可进行类型推断。BeanPostProcessor的典型应用有,处理@Autowired的AutowiredAnnotationBeanPostProcessor,处理@Resource的CommonAnnotationBeanPostProcessor,处理aop的AbstractAutoProxyCreator。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值