之前咱们曾经剖析SpringBoot在run办法时,它会执行的refresh()容器的操作。

在SpringBoot中,refresh()有十几个办法,每个办法的大重要水平是不一样的,咱们通过抓大放小的形式,剖析解决上图3个外围逻辑。

并且曾经钻研完了invokeBeanFactoryPostProcessors和onRefresh的逻辑,剖析它们的原理和设计思维。

之前次要剖析的:

原理有对SpringBoot的主动拆卸配置如何做到的、第三方技术如何进行扩大的、tomcat如何启动的

设计思维有SpringBoot扩大接口设计、有对Tomcat组件的扩大设计、Spring容器形象思维的设计、SpringBoot和第三方技术整合的扩大设计等等。

refresh()还有一个十分要害的操作,就是bean的实例化,明天咱们就来看下refresh最初一个办法—finishBeanFactoryInitialization。

看看它如何执行Bean实例化的流程和设计的。

finishBeanFactoryInitialization之前和之后的操作详情

能够看到,bean的实例化前后,还是做了一些事件的,次要执行的是一些扩大点,比方listener的扩大点执行、LifycycleProcessor的执行。

这一节咱们外围关系的是bean创立流程和设计,所以咱们抓大放小,过就能够。间接来看上面创立bean吧。

preInstantiateSingletons办法的外围脉络

其实bean的实例化大家或多或少都晓得一些。所以我不会特地具体的每一个办法都带大家看。

咱们还是本着先脉络后细节,最初思考的思维来剖析Bean的实例化,当你用这种办法剖析玩后,和你之前剖析对吧下有什么区别,能够感触下。

如果之后大家有诉求须要精读Bean实例化的逻辑,我之后能够思考放在Spring成长记中为大家认真带来Bean实例化的剖析。

这里咱们次要过下它的外围源码就能够了。

因为SpringBoot是为了更好的应用Spring,它是基于Spring的。如果你懂Spring实例化,这块其实十分好了解的。

让咱们来看下吧!

finishBeanFactoryInitialization次要的代码如下所示:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {        // Initialize conversion service for this context.        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));        }        // Register a default embedded value resolver if no bean post-processor        // (such as a PropertyPlaceholderConfigurer bean) registered any before:        // at this point, primarily for resolution in annotation attribute values.        if (!beanFactory.hasEmbeddedValueResolver()) {            beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));        }        // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.        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();    }

这个办法的脉络其实比较清楚,其实最要害的只有一句话:

// Instantiate all remaining (non-lazy-init) singletons.beanFactory.preInstantiateSingletons();

其余的都是给beanFactory补充点货色而已,不是很要害。

这句话从正文很分明的说了,是依据BeanDefinition实例化所有残余的单例非提早初始化的bean。

整个办法我通过先脉络的思维,给大家概括了下:

    public void preInstantiateSingletons() throws BeansException {        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);        //遍历所有beanDefinition,基于beanDefinition创立bean        for (String beanName : beanNames) {            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);            if (isFactoryBean(beanName)) {              //做一些解决FactoryBean              //再从容器中获取bean,如果不存在就创立              getBean(beanName);            }else{              //从容器中获取bean,如果不存在就创立              getBean(beanName);            }              }        // 执行Bean的扩大操作        for (String beanName : beanNames) {            Object singletonInstance = getSingleton(beanName);            if (singletonInstance instanceof SmartInitializingSingleton) {                    smartSingleton.afterSingletonsInstantiated();                    }        }    }

下面的代码是我对源码精简后的逻辑,它的脉络十分清晰了整体如下图所示:

创立bean的外围流程

当你晓得了preInstantiateSingletons办法的外围脉络后,它次要触发的是getBean办法,之后触发了doGetBean。

doGetBean整个办法还是比较复杂的,我还是通过先脉络的思维,抓大放小后,给大家精简了下源码,精简后如下:

    @Overrid    public Object getBean(String name) throws BeansException {        return doGetBean(name, null, null, false);    }  protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {        final String beanName = transformedBeanName(name);        Object bean;            //尝试获取bean,如果容器中有了,就不须要创立了        Object bean = getSingleton(beanName);             if(bean == nul){        //getFromParentBeanfacotry 以后容器没有bean对应的单例对象,尝试从父容器获取,如果父容器为空,则不做解决        //默认父容器空,这里略过               //以后bean的依赖dependsOn解决,递归调用getBean        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);        String[] dependsOn = mbd.getDependsOn();        if (dependsOn != null) {            getBean(dep);                    }        // 单例还是多例的形式创立bean        if (mbd.isSingleton()) {                bean = createBean(beanName, mbd, args);        }else if (mbd.isPrototype()) {            bean = createBean(beanName, mbd, args);        }else {            String scopeName = mbd.getScope();            final Scope scope = this.scopes.get(scopeName);            bean = createBean(beanName, mbd, args);        }    }           //bean的扩大,应用转换器解决bean       T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);                    return (T) bean;}

doGetBean整体代码办法通过,抓大放小,剖析脉络后,其实曾经很清晰了。次要做了这么几件事:

1)getSingleton从容器Beanfactory中的map属性,获取bean,如果非空,间接就能够应用

2)如果容器中没有这个bean,通过判断是否单例,来执行对应的创立bean办法createBean

3)如果以后bean的依赖dependsOn解决,递归调用getBean

4)最初执行了bean的扩大,应用转换器解决bean

doGetBean办法的大体脉络,基本上就是这四步,如下图所示:

真正创立bean的逻辑,到当初咱们还是没有看到,须要持续向下找。doGetBean之后上面就会执行createBean

同理咱们应用之前的办法持续梳理脉络、抓大放小失去如下代码:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)            throws BeanCreationException {、    //Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);    if (bean != null) {       return bean;    }    Object beanInstance = doCreateBean(beanName, mbdToUse, args);    return beanInstance;}

这里createBean其实次要执行了resolveBeforeInstantiation和doCreateBean办法。

1)resolveBeforeInstantiation办法从注解上看,是给动静代理创立一个对象的机会,也就说,能够通过BeanPostProcessor应用动静代理对某些bean间接进行创立。这个十分有意思,也很要害,你想想是不是有的技术就是利用这里进行创立的呢?

2)如果不满足第一个条件,就会应用doCreateBean来创立Bean

整个逻辑如下图所示:

这里终于找到了一种bean创立的形式了,之后应该还有其余形式,比方反射。咱们持续来看doCreateBean。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)      throws BeanCreationException {    BeanWrapper instanceWrapper = null;    //创立bean,bean的实例化    if (instanceWrapper == null) {        instanceWrapper = createBeanInstance(beanName, mbd, args);    }    //bean属性的填充    populateBean(beanName, mbd, instanceWrapper);    //bean 扩大点的触发    initializeBean(beanName, exposedObject, mbd);    //bean 扩大点的增加    registerDisposableBeanIfNecessary(beanName, bean, mbd);    return exposedObject;}

整个doCreateBean办法,通过咱们之前的思路,一样精简完后,脉络也很分明。次要有:

1)创立bean,bean的实例化

2)bean属性的解决

3)bean 扩大点的触发

4)bean 扩大点的增加

doCreateBean的脉络如下图所示:

这里能够看到,除了之前动静代理的截胡,终于找到了bean实例化,创立bean的中央了。

其余对bean属性解决和扩大点,咱们先不看。重点钻研分明bean的创立再说。

createBeanInstance同样被咱们抓大放小后的代码如下:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {   // Make sure bean class is actually resolved at this point.   Class<?> beanClass = resolveBeanClass(mbd, beanName);   //instanceSupplier形式创立bean   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();   if (instanceSupplier != null) {      return obtainFromSupplier(instanceSupplier, beanName);   }   //FactoryMethod形式创立bean   if (mbd.getFactoryMethodName() != null) {      return instantiateUsingFactoryMethod(beanName, mbd, args);   }   //反射的形式创立bean   if (resolved) {      if (autowireNecessary) {         return autowireConstructor(beanName, mbd, null, null);      }      else {         return instantiateBean(beanName, mbd);      }   }   return instantiateBean(beanName, mbd);}

你会发现有多种创立的bean的形式,并不是只有反射,形式次要有:

1)instanceSupplier形式创立bean

2)FactoryMethod形式创立bean

3)反射的形式创立bean

那么再算上之前动静代理创立bean、Factorybean创立的bean。一共曾经有5种能够创立bean的形式, 然而个别咱们还都是通过反射创立的居多。

你可能没有见过其余的形式创立的bean,然而我在一些技术中也见过一些,给大家分享下:

比方

Shiro框架应用Factorybean创立的就比拟多

动静代理创立bean、dubbo就有很多这么创立的

FactoryMethod创立的bean,SpringBoot主动拆卸的时候有时候会用到,之前tomcat启动的时候,TomcatServletWebServerFactory是不是就用到了。

instanceSupplier是Spring5之后才有的,目前我还没有见到啥框架用到过....

好了不论如何,最终你取得了如下的一张图,总结bean的创立形式:

到这里bean 的创立的流程,咱们就大体剖析完了,因为咱们不是剖析Spring,所以就不会再对这外面的每个细节进行剖析了。

之后有机会出Spring成长记的时候,我能够在带大家详细分析吧。

只是相熟SpringBoot中,Spring实例化bean的流程理解到这里根本就能够了。

创立的bean整个流程能够总结下图的几步:

Bean实例化的扩大点设计

最初咱们来看下Bean扩大设计吧,这个其实网上都有一大堆了,然而你肯定要留神,你得会辨别优劣的文章、提炼关键点,要对这些有本人的思考才行。

就像我当初给大家分享的,就是我对扩大点的思考。这个是我始终给大家强调的。

好了,我来简略说下,我对Bean的扩大点设计的思考和了解吧。

在Spring中,Bean实例化的时候,有很多扩大点,这些扩大点其实还是很要害的。

比方:在Spring的生态系统中,很多技术都是通过Bean的扩大点来实现的。而且包含第三方的技术,比方bytetcc分布式事物框架的实现原理和Bean扩大点BeanPostProcessor就有很大的关系、大企业自研框架,能够实现自定义注解的解决、自定义配置文件的解决、给本人开发的bean设置属性等等。

那Bean的扩大点设计了哪些呢?我给大家花了一个图,根本就能详情常见的扩大点了,当然可能还有一些其余的扩大点,不论有多少个,它们都是扩大点,正当利用就好了 ,这个是要害。

Bean实例化时,常见的扩大点的设计如图所示:

小结

如果你去看Bean的实例化的整个流程,其实其中的细节很简单的,如果在简单中找到关键点,是SpringBoot成长记以来,始终想要教给大家的。

最初通过对Bean实例化的剖析,让大家纯熟的利用了之前的学到的先脉络后细节、抓大放小、连蒙带猜、画外围组件图、流程图、看正文等思维和办法。

而且每看一阵子逻辑,要对它做出思考,思考它的设计,它的扩大、它的思维理念等等。

这个是罕用的一套方法论,可能不适宜所有场景,然而大多状况能够让你浏览源码或者钻研技术原理的时候,不那么不安,不会感觉它们太难,能够让你有方向、有办法。

明天的内容,其实没有什么要总结的,比拟重要的就是最初bean 的扩大设计,我就不在反复了。

好了,咱们下一节再见!

本文由博客一文多发平台 OpenWrite 公布!