共计 14685 个字符,预计需要花费 37 分钟才能阅读完成。
IOC 总结
1. IOC 概述
三个问题:
IOC 是什么
- 为什么用它
- 怎么用
1.1 是什么?
两个概念:管制反转,依赖注入
来看一下传统的干活形式:在对象繁多职责准则的根底上,一个对象很少有不依赖其余对象而实现本人的工作,所以这个时候就会呈现对象之间的依赖。而体现在咱们的开发中,就是须要什么对象的时候,就创立什么对象,此时对象创立的控制权在咱们本人手里。当对象创立的太多的时候,就会呈现一个对象更改,就得更改所有依赖它的对象,耦合性大。自主性体现的同时也呈现了对象耦合重大的状况。
这个时候,咱们就会思考,能不能咱们在用的时候间接拿到这个对象去用,而将创建对象的能力交给第三方,这样咱们就不须要关怀对象是怎么创立的了。行将本人的控制权交出去。这就是管制反转
这个时候,就会有另一个问题产生了,对象怎么能力间接被咱们拿来用呢 。对象创立的时候,咱们把这个对象注入到这个对象中,而后就能够应用了。 这就是依赖注入
另一个问题,耦合性怎么被解决掉的?通过管制反转咱们仅仅应用了这个对象,如果对象产生了批改,咱们仅仅须要批改第三方创建对象的形式即可,这个时候难道还会呈现所谓的对象耦合吗?
实现这些工作的就是 IOC 容器,它帮忙咱们创建对象,而后在对象被应用的时候,将对象注入到这个对象中。而因为 IOC 创建对象是通过反射来创立的,所以其速度不如间接 new 对象
还不了解???释怀,听笔者讲一个故事,笔者最喜爱讲故事了
前段时间,天气逐步回暖,鉴于家里没有短袖的状况,笔者只能抉择购买了。这个时候笔者有两种抉择,第一、去生产衣服的厂家间接去买 ( 便宜 );第二、去实体店或者网店购买( 较低廉)。之后,因为笔者属于宅男大军的一员,间接网上购物。
这个场景就是一个典型的管制反转的过程。笔者不须要关注衣服怎么生产的,而是仅仅去 淘宝(IOC 容器)上,寻找本人想要的 衣服 (对象),而后间接拿过去用即可。然而因为存在中间商赚差价,所以 价格更贵(工夫更长)
最初两句话:
管制反转:将本人的控制权交给本人信赖的第三方,甲乙之间不存在依赖关系
依赖注入:凋谢一个端口留给 A,而后在须要的时候,将 B 注入到 A 中。
1.2 为什么用
在下面,笔者曾经很清晰的形容了为什么要应用 IOC,次要起因就是因为对象之间的耦合。
1.3 怎么用
1.3.1 XML
通过书写 XML
配置文件,向容器中增加须要注入的Bean
1.3.2 Annotation
通过 @Configuration
注解指定配置类。
2. IOC 架构
一个图搞定,这个就是 IOC
的架构思路,这不是其执行流程图。
咱们接下来一步一步来解读。
2.1 文言版
在第一章中咱们理解了 IOC
是来帮忙咱们 治理和创建对象 的。
这个时候咱们须要一个承载咱们须要创立信息的容器,即图中的 XML
或者注解,那么有了咱们本人的 BeanDefiniton
信息当前,咱们须要一个接口用来读取这些信息,于是呈现了 BeanDefinitionReader
用来读取咱们本人的 Bean
信息。
那么咱们须要思考一个问题了,那么多的对象怎么生产呢?
答案就是工厂模式。Spring
默认的工厂是 DefaultListableBeanFactory
,没错,Spring
中的所有对象 (容器对象和咱们本人创立的对象) 都是由他创立的。大批量生产对象
这个时候又有了一个问题,咱们不想通过 BeanFactory
间接生产了,须要对这个工厂进行一些特定解决,于是呈现了 BeanFactoryPostProcessor
,用来对工厂做一些特定的解决。 咱们本人能够通过实现这个接口,进行自定义 BeanFactory。又有兄弟说了:我想独自创立一些我喜爱的对象,安顿 ,FactoryBean
诞生了,它能够帮忙咱们创立一个咱们须要的对象(第四局部具体解释他们之间的区别)。
那又有兄弟说了:我想让对立的对象创立之前依照我的形式进行一些非凡的行为,简略,安顿
BeanPostProcessor
呈现了,他提供了两个办法:一个在对象实例化之后初始化之前,执行外部的 Before
办法,在初始化之后,执行 After
办法。(Bean 生命周期,第四局部详解)
这个时候有兄弟有疑难了,不是说 BeanPostProcessor 在创建对象之前执行吗?怎么是创立结束当前才执行的 Before
办法。
如果各位兄弟理解过 指令重排序 这个概念,那么肯定会听过一个案例,创立一个对象须要三步
- 创立空间(实例化)
- 初始化
- 赋值
其中在初始化和赋值会呈现指令重排序
依据这个点,应该能够 get 到一个点,实例化和初始化不一样。
所以又引出了一个点,咱们对 Bean
进行一些操作,怎么操作,必定是批改属性,或者增加一些属性等等,须要期待其在堆中开拓空间即实例化实现当前执行吧。
所以 BeanPostProcessor
的before
办法在实例化之后执行,初始化之前执行。
经验过后面一大堆的操作当前,终于咱们的对象进入咱们兜里了(容器里)。
对于销毁,个别状况下咱们通过 ApplicationContext
拿不到其销毁办法,只能通过其子类实现获取,对于销毁同样的流程,先执行一个销毁之前的操作,而后再销毁。
2.2 理论工作流程
看过 Spring
源码或者听过的都晓得外面有一个办法叫做 refresh
,他实现了好多事件。当然他的行为也代表了整个IOC
容器加载和实例化对象的过程。第三章的代码解读中咱们认真看
执行过程:
- 加载配置文件,初始化零碎环境
Environment
接口 - 筹备上下文环境,初始化一些配置资源
- 创立一个工厂
- 为工厂增加各种环境
- 获取子类本人重写的
BeanFactoryPostProcessor
- 执行容器和咱们本人的
BeanFactoryPostProcessor
- 注册
BeanPostProcessor
- 国际化解决
- 转播器
- 子类初始化
Bean
- 注册监听器,观察者模式
- 实现
Bean
创立 - 公布相应的事件, 监听器
3. IOC 源码解读
写在之前:IOC 的源码比较复杂,所以集体倡议视频形式学习,大家能够 B 站搜寻 阁主梧桐 (笔者认为讲的不错的一个解读),如果大家不喜爱视频的形式,又想深度学习 IOC 源码那么举荐 程序员囧辉 它的博客对于 IOC 的解说十分深刻。另外本文接下来的 Spring 源码,次要是通过图示的办法梳理其流程,作者程度无限。如有谬误请留言。
3.1 上下文配置启动
在创立 ClassPathXmlApplicationContext
的时候,构造方法中执行了这些办法。
说白了,加载了一个解析配置文件门路的加载器;而后又通过零碎环境变量拿到这个配置文件,进行一些配置文件的去空格,转换表达式等等操作(没有进行解析);最初就是那个被我标成红色东东,refresh 办法中它实现了简直所有的工作。上面细聊
3.2 refresh
这个办法简直实现了所有的操作,创立工厂,执行 Processor
等等,实例化对象,开启事件监听等等。
接下来细聊
3.3.1 prepareRefresh()
这个办法的次要作用是为利用上下文的刷新做一些筹备性的工作。校验资源文件,设置启动工夫和沉闷状态等。
3.3.2 obtainFreshBeanFactory()
能够 get 到,它次要就是创立了一个工厂 BeanFactory
,并且解析了配置文件,加载了Bean
定义信息(面试的时候间接答这个点就够了,如果想说的能够将上面的 bean 信息加载聊聊)
没错,标红的就是咱接下来细聊的点
这个就是加载配置文件的过程,留神:此时依然没有解析,解析在标红的上面
这个就是读取的过程,具体解析流程来自 parse
中,这个间接调用了 Java
中的解析 XML
的类库,有趣味自行翻阅,最初返回了一个 Document 对象。
通过 Document 对象,读取外部的标签,执行不同的办法,逻辑和 MyBatis 中解析配置文件的思维雷同,大家自行翻阅。
此时所有的 Bean 定义信息都被保留到了 BeanDefinitionRegistry
接口,而后走子类 DefaultListableBeanFactory
工厂的注册办法
3.3.3 prepareBeanFactory(beanFactory)
为 BeanFactory
筹备一些环境,不便在实例化的时候应用,同时增加容器本人的BeanPostProcessor
3.3.4 postProcessBeanFactory
留给子类扩大的BeanFactoryPostProcessor
,
3.3.5 invokeBeanFactoryPostProcessors(beanFactory)
这个类,波及到了两个接口。
BeanFactoryPostProcessor
BeanDefinitionRegistryPostProcessor
接口,这个接口是BeanFactoryPostProcessor
的子接口,它的优先级比BeanFactoryPostProcessor
更高
它的总体执行流程是:先执行 BeanDefinitionRegistryPostProcessor
的BeanFactoryPostProcessor
,而后再执行BeanFactoryPostProcessor
下图是 BeanDefinitionRegistryPostProcessor
接口的处理过程
BeanFactoryPostProcessor 的解决逻辑
总逻辑就是先分类,曾经解决过的间接跳过,没有解决过的,分类解决,逻辑和下面的雷同。
3.3.6 registerBeanPostProcessors
这个办法的逻辑和下面的一样,只不过下面是间接执行了 BeanFactoryPostProcessor,而这个仅仅注册没执行。
首先拿到工厂中所有的 BeanPostProcessor
类型的Bean
,而后分类解决,排序注册。
3.3.7 initMessageSource()
执行国际化内容
3.3.8 initApplicationEventMulticaster
创立了一个多播器,为增加 Listener
提供反对。
次要逻辑:
- 容器中是否存在
applicationEventMulticaster
,如果存在间接注册 - 如果不存在,创立一个
SimpleApplicationEventMulticaster
,注册到容器中。
3.3.9 onRefresh()
子类扩大
3.3.10 registerListeners()
观察者模式的实现
protected void registerListeners() { | |
// 拿到以后容器中的监听器,注册到多播器中 | |
for (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener); | |
} | |
// 拿到容器中为监听器的 Bean,注册 | |
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); | |
for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); | |
} | |
// 清空开始的事件,到播送器中 | |
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; | |
this.earlyApplicationEvents = null; | |
if (earlyEventsToProcess != null) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent); | |
} | |
} | |
} |
3.3.11 finishBeanFactoryInitialization
这一部分的内容太多了,所以采纳代码和图解的形式来解说。
/** | |
* Finish the initialization of this context's bean factory, | |
* initializing all remaining singleton beans. | |
在上下文工厂中实现所有 Bean 的初始化 | |
*/ | |
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { | |
// 初始化上下文转换服务 Bean | |
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && | |
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { | |
beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); | |
} | |
// 如果不存在前入值解析器,则注册一个默认的嵌入值解析器,次要是注解属性解析 | |
if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); | |
} | |
// 初始化 LoadTimeWeaverAware | |
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); | |
for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName); | |
} | |
// Stop using the temporary ClassLoader for type matching. | |
beanFactory.setTempClassLoader(null); | |
// Allow for caching all bean definition metadata, not expecting further changes. | |
beanFactory.freezeConfiguration(); | |
// Instantiate all remaining (non-lazy-init) singletons. | |
// 实例化,重点 | |
beanFactory.preInstantiateSingletons();} |
下图是创立 Bean 的次要流程
依照途中的序号一个一个说:
BeanDefinition
是否须要合并。BeanDefinition
依据不同类型的配置文件信息,会将Bean
封装到不同的Bean
信息定义类中。比方咱们罕用的配置文件版的GenericBeanDefinition
;注解扫描版的ScannedGenericBeanDefinition
等等。
而在这个过程中就呈现了,父定义和子定义,咱们须要在理论解决定义信息的时候进行合并解决,次要有一下三个方面
- 存在父定义信息,应用父定义信息创立一个
RootBeanDefinition
,而后将自定义信息作为参数传入。 - 不存在父定义信息,并且以后
BeanDefinition
是RootBeanDefintion
类型的,间接返回一份RootBeanDefintion
的克隆 - 不存在父定义信息,并且以后
BeanDefintion
不是RootBeanDefintiton
类型的,间接通过该BeanDefintion
构建一个RootBeanDefintion
返回
下面的流程也是源码中的执行流程
isFactoryBean
。判断是否为FactoryBean
简略介绍一下:FactoryBean
是让开发者创立本人须要 Bean
接口。外部提供了三个办法
T getObject() throws Exception;// 返回的 Bean 信息 | |
Class<?> getObjectType();// 返回的 Bean 类型 | |
default boolean isSingleton() {return true;}// 是否单例 |
当咱们通过 GetBean
间接该 Bean
的时候,获取到的是该工厂指定返回的 Bean
类型。如果想要获取该 Bean
自身,须要通过一个前缀取得&
@Override | |
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {String beanName = transformedBeanName(name); // 解析真正的 BeanName | |
Object beanInstance = getSingleton(beanName, false);// 获取容器中的 bean | |
if (beanInstance != null) {// 如果容器中存在,间接返回该 Bean 是否为 FactoryBea 类型 | |
return (beanInstance instanceof FactoryBean); | |
} | |
// 没有 Bean 信息,查看这个 Bean 信息 | |
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) { | |
// 从父工厂中获取 | |
return | |
((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name); | |
} | |
//MergedBeanDefinition 来查看 beanName 对应的 Bean 是否为 FactoryBean | |
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName)); | |
} |
再来看一个点, 这个就是从容器中获取 Bean 的次要办法,也是解决循环依赖的逻辑
protected Object getSingleton(String beanName, boolean allowEarlyReference) { | |
// 查看以后容器中是否存在该 Bean | |
Object singletonObject = this.singletonObjects.get(beanName); | |
// 如果不存在,且以后 Bean 正在被创立 | |
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) { | |
// 从晚期的容器中获取 Bean | |
singletonObject = this.earlySingletonObjects.get(beanName); | |
// 如果晚期容器也没有且容许创立晚期援用 | |
if (singletonObject == null && allowEarlyReference) { | |
// 获取该 Bean 的 ObjectFactory 工厂 | |
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); | |
// 如果以后工厂不为空 | |
if (singletonFactory != null) { | |
// 创立一个对象实例,此时处于半初始化状态 | |
singletonObject = singletonFactory.getObject(); | |
// 增加到晚期援用中 | |
this.earlySingletonObjects.put(beanName, singletonObject); | |
// 移除创立晚期援用的工厂,因为该 Bean 曾经创立且增加到了晚期容器中,不须要再次进行创立了。this.singletonFactories.remove(beanName); | |
} | |
} | |
} | |
} | |
return singletonObject; | |
} |
来聊一下它是怎么解决循环援用的?
它引入了一个三级缓存的概念
/** 寄存了所有的单例 Bean */ | |
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); | |
/** 寄存了 Bean 创立须要的 ObejctFactory */ | |
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); | |
/** 寄存了晚期创立的 Bean,此时的 Bean 没有进行属性赋值,仅仅通过构造方法创立了一个实例 */ | |
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); | |
// 正在创立的 Bean | |
private final Set<String> singletonsCurrentlyInCreation = | |
Collections.newSetFromMap(new ConcurrentHashMap<>(16)); |
在产生循环援用的时候,它首先通过 ObejctFactory
工厂将 Bean
创立进去,此时的对象并没有进行属性赋值,仅仅在堆中开拓了空间。而后将此时的 Bean
增加到 earlySingletonObjects
容器里,也就是说这个容器中保留的 Bean 都是半成品。而在之后的属性赋值中,因为对象为单例的,所以其援用地址不会发生变化,即对象最终是残缺的。
getBean
。通过这个办法间接创立了所有的对象,这也是 Spring 最外围的办法了
先来看一下它整体的一个流程
它的次要逻辑是:先拿到以后要实例化的 Bean 的实在名字,次要是为了解决FactoryBean
,拿到当前,从以后容器中看是否曾经创立过该 Bean,如果存在间接返回。
如果不存在,获取其父工厂,如果父工厂不为空,而且以后容器中不存在以后 Bean 的信息,则尝试从父工厂中获取 Bean 定义信息,进行 Bean 实例化
如果父工厂为空,将以后 Bean 信息寄存到 alreadyCreated
缓存中。
获取以后 Bean 的合并信息(getMergedLocalBeanDefinition),查看以后 Bean 是否存在依赖,如果存在则判断以后 Bean 和依赖 Bean 是否为循环依赖,如果不是循环依赖则先创立依赖 Bean
判断以后 Bean 的作用域。
如果以后 Bean 是单例对象,间接创立 Bean 实例
如果以后 Bean 是多例对象,将以后 Bean 信息增加到正在创立多例缓存中,创立结束当前移除
如果以后 Bean 是其余类型,如 Requtst,Session 等类型,则自定义一个 ObejctFacotry 工厂,重写 getObject 办法,创建对象
对象创立当前,判断以后对象是否为本人须要的对象,如果是间接返回;如果不是进行类型转换,如果类型转换失败,间接抛异样
接下来看一眼 CreateBean
的执行
这个办法次要实现的事件是:通过 Bean 的名字拿到对应的 Class 对象;如果以后 Bean 获取到的 Class 对象不为空且该 RootDefintiton 能够间接获取到该 Bean,克隆一份 Bean 定义信息,不便之后应用。
验证以后 Bean 上的 @Override 信息。执行 BeanPostProcessor,返回一个代理对象(如果存在代理的话)
如果不存在代理,则间接创立 Bean
接下来咱们来聊一下这个玩意——resolveBeforeInstantiation
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { | |
Object bean = null; | |
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { | |
// Make sure bean class is actually resolved at this point. | |
// 以后定义信息不是合并,且存在 Bean 增强器 | |
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { | |
// 获取 Bean 的 Class 类型 | |
Class<?> targetType = determineTargetType(beanName, mbd); | |
if (targetType != null) { | |
// 如果不为 null,则执行前置处理器 | |
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); | |
if (bean != null) { | |
// 如果前置处理器不为 null,则后置处理器执行,跳过 spring 默认初始化 | |
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); | |
} | |
} | |
} | |
// 代表曾经再实例化之前进行了解析 | |
mbd.beforeInstantiationResolved = (bean != null); | |
} | |
return bean; | |
} |
来吧,持续,看一下那个前置处理器逻辑
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {for (BeanPostProcessor bp : getBeanPostProcessors()) { | |
// 拿到工厂中的所有的 BeanPostProcessor | |
if (bp instanceof InstantiationAwareBeanPostProcessor) { | |
// 找到所有咱们须要的增强器 | |
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; | |
// 返回一个代理实例 | |
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); | |
if (result != null) {return result;} | |
} | |
} | |
return null; | |
} |
后置处理器就不看了,就调用了所有的后置处理器,而后执行了一遍,没有其余逻辑。
接下来持续咱们的正题:doCreateBean
其大抵流程如上图:
先判断当前是否单例,而后从 FactoryBean 缓存中看一下是否存在正在创立的 Bean,如果存在拿出,如果不存在则创立一个以后 Bean 的包装类实例。而后拿到这个类的实例和实例类型,执行当前后置处理器。
以后 Bean 是否为单例,是否容许循环依赖,时候正在进行创立,如果是,创立一个以后 Bean 的 ObejctFactory 以解决循环依赖的问题
填充 Bean 的属性,进行 Bean 的实例化。
查看晚期容器缓存中(缓存中的二级缓存中是否有该 Bean)。如果有,则阐明存在循环依赖,则进行解决
先看循环依赖吧
if (earlySingletonExposure) { | |
// 从晚期的 Bean 容器中拿到实例对象,此时的 Bean 必然存在循环依赖 | |
Object earlySingletonReference = getSingleton(beanName, false); | |
if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { | |
// 获取依赖的全副 Bean 信息 | |
String[] dependentBeans = getDependentBeans(beanName); | |
Set < String > actualDependentBeans = new LinkedHashSet < > (dependentBeans.length); | |
for (String dependentBean: dependentBeans) { | |
// 革除这些 Bean 信息,此时的 Bean 曾经是脏数据了 | |
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { | |
// 无奈清理存入 actualDependentBeans 中 | |
actualDependentBeans.add(dependentBean); | |
} | |
} | |
if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException} | |
} | |
} | |
} | |
// Register bean as disposable. | |
try {registerDisposableBeanIfNecessary(beanName, bean, mbd); | |
} catch (BeanDefinitionValidationException ex) { | |
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); | |
} |
接着来,createBeanInstance
Spring 提供了三种形式创建对象的包装:
- 通过供给者对象对象间接创立。
obtainFromSupplier
- 通过工厂办法间接创立。
-
默认创立。
- 构造方法是否须要主动注入
- 构造方法不须要主动注入,调用默认的构造方法
这个办法执行结束当前,你应该通晓的一个点是:此时对象实例曾经创立了,剩下的就是执行一系列增强器和初始化办法,属性填充等等。
咱们依照代码执行程序来,属性填充即populateBean
这个办法执行逻辑:
首先判断传入的 Bean 是否为 null,如果为 null 则判断 Bean 定义信息中是否存在属性值,如果存在,异样;如果不存在跳过
以后 Bean 定义信息是否为合并当前的,如果是且此时的工厂中存在 InstantiationAwareBeanPostProcessors,那么在属性填充之前进行批改 Bean 的信息
拿到所有的属性值,解析属性值的主动注入形式,Type 或者 Name,进行主动注入
判断是否存在 InstantiationAwareBeanPostProcessors, 批改之前设置的属性
判断是否存在依赖查看,查看依赖
属性赋值
接下来看执行初始化办法,就是调用 BeanPostprocessor,init
等办法
这个就是这个办法的执行流程图,置信到这个中央,大家应该对于为什么 BeanPostProcessor 的 before 办法会在 init 办法执行理解了。这个办法的作用仅仅是用来进行一个生命周期的打印,对象在之前曾经创立了。
接下来看一下销毁的办法。registerDisposableBeanIfNecessary
对于单例 Bean 来说,Spring
将须要销毁的 Bean 寄存到了 disposableBeans
缓存中,通过 DisposableBeanAdapter
封装了销毁 Bean
对于其余作用域来说,自定义了销毁回调函数,不过最初还是封装为DisposableBeanAdapter
在封装为 DisposableBeanAdapter
的过程中,会首先判断该 Bean 中是否存在 destroy 办法,而后给赋值给 destroyMethodName 变量。再次判断这个办法的参数,如果参数的个数大于 1,则抛出异样
3.3.12 finishRefresh
这个办法进行了一系列的资源清理和
protected void finishRefresh() { | |
// 清空上下文资源缓存 | |
clearResourceCaches(); | |
// 初始化生命周期处理器 | |
initLifecycleProcessor(); | |
// 将曾经刷新结束的处理器流传(扔到)生命周期处理器中 | |
getLifecycleProcessor().onRefresh(); | |
// 推送上下文刷新结束的工夫到相应的监听器 | |
publishEvent(new ContextRefreshedEvent(this)); | |
// Participate in LiveBeansView MBean, if active. | |
LiveBeansView.registerApplicationContext(this); | |
} |
initLifecycleProcessor,这个办法极具简略,就看一下以后 Bean 中是否存在生命周期处理器,如果存在间接应用这个,如果不存在则创立一个默认的,并且注册为一个单例的扔到容器中。
4. 常见题目
4.1 Bean 的生命周期?
Spring 官网解释在 BeanDefinition 接口的正文里
答:Bean 残缺的生命周期是:
- 设置一系列
Aware
接口的性能 - 实例化 Bean
- 调用
BeanPostProcessor
的before
办法 - 执行
InitializingBean
接口办法afterPropertiesSet
- 执行
init
办法 - 调用
BeanPostProcessor
的postProcessAfterInitialization
办法 - 调用
DestructionAwareBeanPostProcessors
接口的postProcessBeforeDestruction
办法 - 调用
destory
办法
4.2 FactoryBean 和 BeanFactory 的区别
答:BeanFactory
是 Spring
默认生产对象的工厂。
FactoryBean
是 Spring
提供的一个生产特定类型和特定对象的工厂。例如 Mybatis-spring
中的 SqlSessionFactoryBean
就是通过这种办法创立的。
4.3 什么是循环依赖?Spring 如何解决循环依赖的?
答:循环依赖是指:在创立 A 对象的时候须要注入 B 对象;在创立 B 对象的时候须要注入 A 对象,两者相互依赖。
呈现循环依赖有两种状况:
- 结构器依赖 ( 无奈解决)
- 属性注入(能够解决)
解决循环依赖,Spring 引入了三级缓存的概念。下面的源码解说中介绍过
singletonObjects
寄存了所有的单例Bean
,此时所有的Bean
信息都是残缺的earlySingletonObjects
寄存了晚期的Bean
,此时仅仅创立了一个Bean
实例,未进行属性填充singletonFactories
寄存了Bean
的工厂
Spring
通过将创立 Bean
的工厂裸露进去,而后在呈现循环依赖的时候通过这个工厂常见一个 bean
,而后将这个Bean
注入,因为对象是单例的,所以在接下来的属性填充中,能够保障为同一个对象,至此,循环依赖解除。
应用 三太子敖丙 的一句话:解决循环依赖的过程就是力扣中的第一题两数之和的过程
4.4 什么是 IOC
答:IOC 存在两个点:
- 管制反转。将常见对象的控制权交给第三方,这里的第三方就是
Spring
- 依赖注入。在类中须要应用到的对象,全副通过反射从第三方容器注入而不是本人创立。这里的第三方容器即
Spring
4.5 ApplicationContext 和 BeanFactory 的区别
答:
ApplicationContext
采纳了立刻加载,即加载配置文件的时候就创立了对象。BeanFactory
采纳了延时加载的形式,应用的时候才创立。- 对于
BeanPostProcessor
和BeanFactoryProcessor
而言,BeanFactory
是手动注册,ApplicationContext
采纳了主动注册。
4.6 Spring 框架中都用到了哪些设计模式?
答:
- 单例模式。这个不须要多说
- 代理模式。
AOP
应用到的 - 装璜着模式。
BeanWrapper
- 工厂模式。BeanFactory,创建对象的时候
- 模板办法模式。JDBCTemplate
- 观察者模式。各种事件监听
- ……
更多原创文章和 Java 系列教程请关注公众号 @MakerStack