关于java:刨析SpringIOC及其启动原理

3次阅读

共计 14685 个字符,预计需要花费 37 分钟才能阅读完成。

IOC 总结

1. IOC 概述

三个问题:

  1. IOC 是什么

    1. 为什么用它
    2. 怎么用

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 进行一些操作,怎么操作,必定是批改属性,或者增加一些属性等等,须要期待其在堆中开拓空间即实例化实现当前执行吧。

所以 BeanPostProcessorbefore办法在实例化之后执行,初始化之前执行。

经验过后面一大堆的操作当前,终于咱们的对象进入咱们兜里了(容器里)。

对于销毁,个别状况下咱们通过 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 更高

它的总体执行流程是:先执行 BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor,而后再执行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 的次要流程

依照途中的序号一个一个说:

  1. BeanDefinition是否须要合并。BeanDefinition依据不同类型的配置文件信息,会将 Bean 封装到不同的 Bean 信息定义类中。比方咱们罕用的配置文件版的 GenericBeanDefinition;注解扫描版的ScannedGenericBeanDefinition 等等。

而在这个过程中就呈现了,父定义和子定义,咱们须要在理论解决定义信息的时候进行合并解决,次要有一下三个方面

  • 存在父定义信息,应用父定义信息创立一个RootBeanDefinition,而后将自定义信息作为参数传入。
  • 不存在父定义信息,并且以后 BeanDefinitionRootBeanDefintion类型的,间接返回一份 RootBeanDefintion 的克隆
  • 不存在父定义信息,并且以后 BeanDefintion 不是 RootBeanDefintiton 类型的,间接通过该 BeanDefintion 构建一个 RootBeanDefintion 返回

下面的流程也是源码中的执行流程

  1. 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 都是半成品。而在之后的属性赋值中,因为对象为单例的,所以其援用地址不会发生变化,即对象最终是残缺的。

  1. 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
  • 调用 BeanPostProcessorbefore办法
  • 执行 InitializingBean 接口办法afterPropertiesSet
  • 执行 init 办法
  • 调用 BeanPostProcessorpostProcessAfterInitialization办法
  • 调用 DestructionAwareBeanPostProcessors 接口的 postProcessBeforeDestruction 办法
  • 调用 destory 办法

4.2 FactoryBean 和 BeanFactory 的区别

答:BeanFactorySpring 默认生产对象的工厂。

FactoryBeanSpring 提供的一个生产特定类型和特定对象的工厂。例如 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采纳了延时加载的形式,应用的时候才创立。
  • 对于 BeanPostProcessorBeanFactoryProcessor而言,BeanFactory是手动注册,ApplicationContext采纳了主动注册。

4.6 Spring 框架中都用到了哪些设计模式?

答:

  • 单例模式。这个不须要多说
  • 代理模式。AOP应用到的
  • 装璜着模式。BeanWrapper
  • 工厂模式。BeanFactory,创建对象的时候
  • 模板办法模式。JDBCTemplate
  • 观察者模式。各种事件监听
  • ……

更多原创文章和 Java 系列教程请关注公众号 @MakerStack

正文完
 0