美文网首页
Spring核心源码深度解析(六)实例化和初始化对象

Spring核心源码深度解析(六)实例化和初始化对象

作者: 七天0 | 来源:发表于2020-07-08 14:03 被阅读0次

    ​Spring 创建对象

    在上一章我们对invokeBeanFactoryPostProcessors的重要部分进行了详细的介绍,总算到了我们的Spring创建对象的过程了,本章会接着前面的refresh进行续写。

    registerBeanPostProcessors(beanFactory)

    这个方法的特性和invokeBeanFactoryPostProcessors(beanFactory);其实差不太多,也是对后置处理器的一些操作,但这个方法的重量缺少了很多,相信读者有了invokeBeanFactoryPostProcessors(beanFactory);的经验应该能够自行理解其基本意义。

    initMessageSource();

    初始化国际化资源,这里只是对一些资源加载的方式进行规范。

    initApplicationEventMulticaster();

    创建ApplicationEventMulticaster这么一个类,这个类是事件操控的核心,我们先跳过,这里不会影响整体Bean初始化

    onRefresh();

    空方法

    registerListeners

    注册监听器

    finishBeanFactoryInitialization(beanFactory)

    总算到我们真正创建Bean的核心方法了,通过这个方法的名字就可以猜到,这就是我们Spring用来创建对象的核心方法,如果不相信的话我们在这里调试一下,首先看第一张图


    image

    singletonObjects就是我们的实例对象,这里不同的Spring版本可能singletonObjects所在的类会有一些区别,那么如果singletonObjects数量发生改变说创建对象就是在这里实现的,我们调试一下


    image image

    可以看到singletonObjects的数量确实增加了几个,而且这几个就是我们所创建的,那么我们就开始对其进行分析,在对finishBeanFactoryInitialization深度分析时,笔者只会对一些核心点进行解释说明,因为内容确实太多,有些比较特殊的我就一笔带过,话不多说看代码

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // 这里不知道CONVERSION_SERVICE_BEAN_NAME有什么用
        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.
        //检查Spring中是否存在类型转换
        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);
        }
    ​
        // 禁止使用临时类加载器进行类型匹配
        beanFactory.setTempClassLoader(null);
    ​
        // Allow for caching all bean definition metadata, not expecting further changes.
        //允许缓存所有的bean的定义数据
        beanFactory.freezeConfiguration();
    ​
        // Instantiate all remaining (non-lazy-init) singletons.
        //重点,准备bean实例
        beanFactory.preInstantiateSingletons();
      }
    

    注释比较详细,这里其实没做什么事情,核心方法是beanFactory.preInstantiateSingletons();我们点进去

      public void preInstantiateSingletons() throws BeansException {
        if (logger.isTraceEnabled()) {
          logger.trace("Pre-instantiating singletons in " + this);
        }
        // Iterate over a copy to allow for init methods which in turn register new bean definitions.
        // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
        //拿到所有的bd名字
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    ​
        // Trigger initialization of all non-lazy singleton beans...
        //循环并判断是不是不是懒加载的,是不是FactoryBean,然后对bd进行bean创建
        for (String beanName : beanNames) {
          RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
          if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (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) {
                  getBean(beanName);
                }
              }
            }
            else {
              getBean(beanName);
            }
          }
        }
    ​
        // Trigger post-initialization callback for all applicable beans...
        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();
            }
          }
        }
      }
    

    这里首先执行RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);将我们的BeanDefinition合并,最后都采用RootBeanDefinition声明,然后判断是不是单例对象,是不是FactoryBean,如果不是就会进入getBean(beanName);我们在跟进


    image

    这里为什么是GetBean而不是创建对象,其实 Spring在很多地方都会获取对象,所以不可能每次获取都是创建对象,而应该是先查询有没有,再创建就像我们使用的缓存技术一样。我们继续


    image

    进入这句代码:Object sharedInstance = getSingleton(beanName);


    image

    这里先简单分析下,如果获取的对象是没有完全创建的,那么的singletonObject为空,isSingletonCurrentlyInCreation(beanName)也会为false那么判断会退出,记住这个isSingletonCurrentlyInCreation,然后我们继续


    image

    这些都不重要,我们往下看----

    Bean实例化

    image

    这里的return createBean(beanName, mbd, args);是表达式语法,其实就是一个回调方式,然后我们调试进入getSingleton,


    image

    这里会做一些判断,如果没有实例化这个对象那么
    它就会执行这段代码beforeSingletonCreation(beanName);我们看看这段代码做了什么


    image

    他会将我们的对象标识为正在创建,记住这个标识


    image

    然后再往下走回走到singletonObject = singletonFactory.getObject();


    image

    可以看到这里产生回调,不熟悉函数式的朋友们可以先忽略它,我们进入createBean(beanName, mbd, args);


    image image

    前面都不重要,可以看到创建对象的代码在这一行Object beanInstance =

    doCreateBean(beanName, mbdToUse, args);笔者这里再啰嗦一下这段代码Object bean =resolveBeforeInstantiation(beanName, mbdToUse); image

    这里笔者认为设计的有些累赘了,它的目的其实就是如果程序员定义的对象实现这个InstantiationAwareBeanPostProcessor接口,那么Spring就会认为这个对象不需要经过Spring的完整生命周期,需要脱离Spring管理的意思,然后直接return掉,但我想Spring可能也是为了扩展的开放性吧,毕竟Spring的设计考虑的十分周全。好了,我们回到代码Object beanInstance = doCreateBean(beanName, mbdToUse, args);


    image

    这里定义了一个instanceWrapper,读者可以将其当做一个有一些功能的对象,然后进入instanceWrapper = createBeanInstance(beanName, mbd, args);


    image

    这里主要是获取class类型,然后判断是不是FactoryMethod创建对象,如果不是就继续往下:


    image

    这里其实是一种缓存技术,如果我们在前面已经确认了这个类的构造器是什么,那么久不会再进行下文的构造器策略,直接调用构造器方法,当然我们这里暂时没有。


    image

    这里是Spring对实例构造器的一个策略,我们都知道一个类创建一个对象无非就两种情况,调用有参构造函数或者无参构造函数,那么我们先从无参构造说起,看下图


    image

    假如我们的ctors为空 也就是说我们的对象是用的无参构造,那么会执行到return instantiateBean(beanName, mbd);,我们跟踪此代码


    image

    在跟踪beanInstance =getInstantiationStrategy().instantiate(mbd, beanName, parent);->return BeanUtils.instantiateClass(constructorToUse);->


    image

    最终可以看到我们的反射代码newInstance。介绍完无参构造器创建对象后,我们开始探讨第二种有参构造创建对象的方式,回到IDEA,首先我们对User1类新增一个有参构造器,


    image

    然后我们开始debug调试,我们以User1类作为调试类


    image

    然后进入determineConstructorsFromBeanPostProcessors方法


    image

    这里会拿出很多后置处理器,但前面的基本都是默认实现,真正干活的是这个类AutowiredAnnotationBeanPostProcessor
    然后进入:


    image

    前面的方法是检查是否存在LOCKUP方法,我们这里没有执行下一步


    image

    这里也没做什么事情,只是想从缓存中拿出有没有确定好的构造器,后面会获取所有构造方法,判断方法是不是加了@Awtowire注解,基本都会跳过,我们直接跳到核心代码


    image

    这里其实就是确认构造器,从我们的断点来看,当我们拿到的构造函数只有一个,且参数大于0,从我们目前的情况来看是符合的,那么就会返回我们构造器。拿到构造器后我们再看


    image

    我们会拿到我们所创建的构造器,那如果我们换一种方式采用多个构造器


    image 我们调试发现 image

    返回的值为null,其实这也很好理解,在没有指定某个构造器primary时,如果我们创建多个构造器,Spring不知道如何决策,就只执行默认构造器


    image ,在上文我们对无参构造的方式进行了介绍,现在我们对有参构造进行说明 image

    autowireConstructor()->autowireConstructor();
    这里我们思考下如何用有参构造的方式创建对象,首先是不是确定我们的类,其次是不是需要确定构造器,然后我们还需要确定参数的值是什么,那么下面的操作就是确定参数的值到底是什么,我们回到IDEA:


    image

    这里没什么需要多说的


    image

    这里看有没有缓存,显然我们没有


    image

    这里的代码个人认为Spring可能为了防止其他地方复用这段代码,所以判断构造器是不是为空


    image

    这里autowiring肯定不会false,然后进入有参构造十分关键的代码


    image

    通过方法名我们都能大概猜出来这里就是获取有参构造传入的参数值,前面我们说过,确定构造器还需要构造参数的值才能成功创建一个对象,那么我们看这个代码能否获取参数值


    image 很显然这里并没有获取,道理很简单,因为我们并没有对User1类指定构造器参数值,如果我们继续运行下去,Spring会抛出异常,表示无法创建这个类,这样很好说明,我们想要使用有参构造创建对象,确定没有给定参数值,这必然会报错, image

    那么怎样才能获取参数值呢,这里笔者会采用两种方式:第一种方式笔者会改变Spring源码


    image 然后我们再次运行 image

    ,发现已经有值,然后User1类会创建对象成功,当然我们去改变源码是不是不太合适啊,所以采用第二种方式后置处理器,代码如下:


    image

    依旧可以实现有参构造的方式,

    读到这里,读者是否有些恍然大悟,领略到了笔者前面提出的Spring的后置处理器的作用和设计的精妙,这样就可以实例化一个对象了,当然这还没有完,Spring还会对其他特别的有参构造进行解析,因为设计思想较为复杂,读者有兴趣可以自行深入了解,那么我们的对象实例化就算结束了,回到IDEA, image

    这里我们返回了我们的对象。

    Bean初始化

    image

    在创建完对象后,Spring将会对象进行初始化,我们跟踪applyMergedBeanDefinitionPostProcessors这段代码:


    image

    可以看到这又是循环后置处理器,获取属于MergedBeanDefinitionPostProcessor,然后我们继续跟踪bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);在查看这个方法到底会执行哪些处理器,


    image

    我们在对其中之一后置处理器点开


    image image

    其实这里的处理器就是对我们Spring的生命周期的处理,但这里并不会执行,而是采用元信息的方式将它保存起来,好了,我们继续往下看


    image

    前面的代码不重要,我们直接看到addSingletonFactory(beanName, () ->
    getEarlyBeanReference(beanName, mbd, bean));


    image

    这里会有四个集合,第一个集合是singletonObjects存放单例Bean的,第二个singletonFactories
    存放的是ObjectFactory工厂Bean,这个ObjectFactory个人认为和Bean并无太大区别,直接间接存取而已,第三个earlySingletonObjects是提前存储的对象,最后一个registeredSingletons存放的是BeanName,用来解决排序问题,好了我们继续


    image

    接下来可以看到Spring的属性注入的核心代码populateBean(beanName, mbd,
    instanceWrapper);,在对这段代码分析之前,我们先修改一下我们的工程,首先将User2改成


    image 再将User1改成 image

    这条调整的目的是为了演示循环依赖,好了,
    然后我们重新debug


    image

    这里先对User1属性注入,我们点进去


    image

    这里又有对后置处理器的处理,这里后置处理器的作用是如果你实现了InstantiationAwareBeanPostProcessors的postProcessAfterInstantiation方法,那么Spring会认为你牛逼,你要自己初始化,那我就中断这个Bean的后续一切操作,就等于脱离Spring的生命周期管理,其实这也是可以想到的,不一定所有的对象都是需要Spring帮我们处理,这里Spring的设计考虑的十分周全,我们回到IDEA


    image

    这里有一个重要的属性叫AutowireMode,为什么说他重要,我们会在Spring-Mybatis章节详细说明,这里先跳过,因为我们默认的是NO,然后我们进入这里


    image

    看方法名能够大概猜到这里就是属性注入的关键,我们断点


    image

    然后我们直接跳到AutowiredAnnotationBeanPostProcessor,进入这个方法PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);首先获取我们的InjectionMetadata,注入需要的元数据


    image

    然后->metadata.inject(bean, beanName, pvs);->element.inject(target, beanName, pvs);

    然后我们先看最后一行代码 image

    field.set(bean, value);懂反射的小伙伴们都知道,我们可以通过Field类对一个类的对象属性赋值,所以Spring默认也采用的这种方式,那么我们现在有了类,缺少value,而这个value在元数据中已经显示User2类,所以我们需要拿到User2的对象才行,回到IDEA上面的代码,其中有一行


    image

    然后我们跟踪下resolveDependency->doResolveDependency->descriptor.resolveCandidate


    image

    最终又回到了getBean,也就是说Spring会从工厂里拿,而这个时候我们的工厂并没有创建它,所以User2创建对象后依旧会进行进入属性注入的方法


    image

    这个时候我们跳到了User2的属性注入方法,然后一样User2里面有User1这个类,所以又会去获取User1的对象,但是我们的User1并没有创建完成,属于创建中的状态,那么Spring是如何解决的呢?我们继续跟踪代码


    image

    这里的代码是我们先创建了User1然后属性注入user2,这时工厂没有User2对象,于是创建User2,User2创建完后开始对内部的属性user1注入,这时会跳到上图,然后我们再跟踪进去


    image

    singletonObject == null 目前是为空的,因为我们的user1还在创建中,然而这一行代码我们运行isSingletonCurrentlyInCreation(beanName)


    image

    返回的是true,还记我们创建对象时会将对象标识为正在创建吗?这里就起到了效果,那么if会成立,这个时候就会从我们的ObjectFactory获取,在上文提到过ObjectFactory是间接存取,


    image 随后User2拿到了User1的对象,然后User1也会拿到User2的对象因此解除循环依赖,创建对象成功,最后 image

    这里会获取我们前文存储的生命周期元数据,并执行


    image image

    我们用一张图回顾下我们的循环依赖


    image

    目前对Spring的整体核心源码基本已经告一段落,后面会对AOP、Spring-Mybatis、事物、数据来源、事件等知识结合面试题的方式进行嵌套描述。

    相关文章

      网友评论

          本文标题:Spring核心源码深度解析(六)实例化和初始化对象

          本文链接:https://www.haomeiwen.com/subject/dhpqcktx.html