Spring IOC容器启动全流程源码解析

本文详细介绍了Spring IOC容器的启动流程,从基于注解的配置方式出发,深入到BeanFactory和ApplicationContext的关系,以及Bean的注册过程。通过分析`doRegisterBean`方法,展示了BeanDefinition的生成和注册。接着,文章探讨了`refresh()`方法中的关键步骤,如`prepareBeanFactory`,`finishBeanFactoryInitialization`,以及Bean的实例化、属性装配和初始化。文章还提到了FactoryBean的概念及其在实例化过程中的作用。通过对整个流程的剖析,读者能够全面理解Spring容器如何管理和初始化Bean。

在讲解spring ioc容器启动流程之前,我们先看下继承结构,方便梳理下文中大量的类、接口之间的关系。

这个是BeanFactory,作为顶层容器。

这个是我们常见的ApplicationContext

 

 

首先启动容器,有xml和注解这两种基本方式,我们下面的代码是基于注解方式,中间会穿插对xml方式的解释,大同小异,可以放心食用

 

SpringConfig类就是一个配置类

 

 

点进去看下这个注解容器的构造方法

 

无参构造方法实现

 

再看下是怎么注册咱们自定义的SpringConfig类的

 

跟着register(conmponentClasses)方法一路点进去,来到了doRegisterBean方法,这个方法的大致实现逻辑是首先生成一个beanDefinition,

然后解析下咱这个配置类SpringConfig的注解,看下是否是Primary、是否是lazy懒加载,接着new一个BeanDefinitionHolder,

这个holder其实就是对beanDefinition、beanName还有alias做了一层封装而已,这些完成后,开始注册这个beanDefinition

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,

      @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,

      @Nullable BeanDefinitionCustomizer[] customizers) {


   //生成一个abd

   AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);

   if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {

      return;

   }


   abd.setInstanceSupplier(supplier);

   ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);

   abd.setScope(scopeMetadata.getScopeName());

   String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));


   //解析bean上的注解

   AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

   if (qualifiers != null) {

      for (Class<? extends Annotation> qualifier : qualifiers) {

         if (Primary.class == qualifier) {

            abd.setPrimary(true);

         }

         else if (Lazy.class == qualifier) {

            abd.setLazyInit(true);

         }

         else {

            abd.addQualifier(new AutowireCandidateQualifier(qualifier));

         }

      }

   }

   if (customizers != null) {

      for (BeanDefinitionCustomizer customizer : customizers) {

         customizer.customize(abd);

      }

   }


   //new一个BeanDefinitionHolder,这个holder封装了BeanDefinitionbeanNamealias

   BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);

   definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

   //注册bean,这里的registry是啥?就是AnnotationConfigApplicationContext

   //就是AnnotationConfigApplicationContext继承了GenericApplicationContext

   //GenericApplicationContext里有个DefaultListableBeanFactory

   //DefaultListableBeanFactory有个registerBeanDefinition用于注册bean

   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

}

 

我们进入DefaultListableBeanFactory的registerBeanDefinition方法里看下注册beanDefinition的逻辑,可以看到,所谓的注册bean,本质上就是

把这个beanDefinition放到了DefaultListableBeanFactory的beanDefinitionMap里

 

 

 

 

 

到这里,我们的配置类SpringConfig.class已经注册到ioc容器里了(beanDefinition放到了DefaultListableBeanFactory的beanDefinitionMap里)

 

下面进入最最重点的AbstractApplicationContext的refresh()方法:

先看下obtainFreshBeanFactory,针对注解这种方式,这个方法完成后,会返回给我们一个beanFactory,也就是DefaultListableBeanFactory

 

 

下面是针对xml方式,refreshBeanFactory的具体实现逻辑

 

prepareBeanFactory,提前对我们的beanFactory做一些准备工作

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {

   // Tell the internal bean factory to use the context's class loader etc.

   //设置BeanFactory的类加载器,由于BeanFactory需要加载类,因此需要类加载器

   //这里设置为当前ApplicationContext的类加载器

   beanFactory.setBeanClassLoader(getClassLoader());

   //设置BeanExpressionResolver

   if (!shouldIgnoreSpel) {

      beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

   }

   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));


   // Configure the bean factory with context callbacks.

   //添加一个BeanPostProcessor

   //实现了Aware接口的几个特殊的beans在初始化的时候,这个processor负责回调

   /**

    * 如果在某个类里面想要使用Spring的一些东西,就可以通过实现XXXAware接口告诉Spring,

    * Spring看到后就会送过来,而接受的方式是通过实现接口唯一的方法setXXX.

    * 比如ApplicationContextAwareBeanNameAware

    */

   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

   //下面几行代码的意思是:如果某个bean依赖于以下几个接口的实现类,在自动装配时忽略它们

   //Spring会通过其他方式来处理这些依赖

   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);

   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);

   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);

   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);

   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

   beanFactory.ignoreDependencyInterface(ApplicationStartup.class);



   // BeanFactory interface not registered as resolvable type in a plain factory.

   // MessageSource registered (and found for autowiring) as a bean.

   /**

    * 下面几行就是为特殊的几个bean赋值,如果有bean依赖了以下几个,会注入这边相应的值

    * "当前ApplicationContext持有一个BeanFactory",就是指这里的第一行

    * ApplicationContext继承了ResourceLoaderApplicationEventPublisherMessageSource

    * 所以对于这几个,可以赋值为this,注意this是一个ApplicationContext

    *

    */

   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);

   beanFactory.registerResolvableDependency(ResourceLoader.class, this);

   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);

   beanFactory.registerResolvableDependency(ApplicationContext.class, this);



   // Register early post-processor for detecting inner beans as ApplicationListeners.

   //这个BeanPostProcessor也很简单,在bean实例化后,如果是ApplicationListener的子类

   //那么将其添加到Listener列表中,可以理解为:注册事件监听器

   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));



   // Detect a LoadTimeWeaver and prepare for weaving, if found.

   //处理特殊bean"LoadTimeWeaver",这个不是重点

   if (!IN_NATIVE_IMAGE && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {

      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));

      // Set a temporary ClassLoader for type matching.

      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));

   }


   // Register default environment beans.

   //spring帮我们默认注册一些有用的bean,我们也可以选择覆盖



   //如果没有定义"environment"这个bean,那么Spring"手动"注册一个

   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {

      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());

   }

   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {

      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());

   }

   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {

      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());

   }

   if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {

      beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());

   }

}

 

下面我们回到refresh方法,继续向下看,关注invokeBeanFactoryPostProcessor方法,调用BeanFactoryPostProcessor实现类的postProcessorBeanFactory方法,

invokeBeanFactoryPostProcessor方法执行完毕后,我们代码中自定义的bean都已经注册到beanFactory中了(包括我们自定义的beanPostProcessor,也作为bean注册到beanDefinitionMap中了),

下一步是注册beanPostProcessor(将processor放入到AbstractBeanFactory的beanPostProcessors这个列表里,后面初始化时从这个列表里取processor进行相应的方法回调)

 

 

下面我们进入重点中的重点finishBeanFactoryInitialization(beanFactory)方法,到这一步时,我们的beanFactory已经做好全部准备工作,bean已经注册到

工厂里,各种processor也已经注册,供接下来的bean初始化使用。这一步将完成bean的三大生命周期:实例化、属性装配、初始化

 

 

 

一路点进去,最终进入到AbstractBeanFactory的doGetBean方法,首先关注这里的getSingleton方法,这是spring中利用三级缓存解决循环依赖的关键

 

瞅一眼这个方法的具体实现:

先从一级缓存(singleObjects)取bean实例对象,没有则从二级缓存(earlySingletonObjects)取,还没有则从三级缓存(singletonFactories)取。

然后我们回到doGetBean方法,执行到createBean,实例化、属性装配、初始化也是在这个方法里完成的

 

进入到AbstractAutowireCapableBeanFactory的doCreateBean方法,这里包含了bean声明周期三大阶段:实例化、属性装配、初始化(在属性装配和初始化之间及初始化之后会有相应的aware、beanPostProcessor等执行),

这里出现一个BeanWrapper,这个wrapper就是根据beanDefinition完成实例化的bean的一层封装。

 

下面我们看实例化这一阶段是如何实现的

我们看下无参构造bean实例的方式instantiateBean():

这里进入到了SimpleInstantiationStrategy的instantiate方法(通过方法参数可知这是无参实例化策略),该类是实现了InstantiationStrategy接口,该接口有三个方法,分别按照无参、有参、工厂方法这三种策略来定义

 

 

最终通过反射或cglib代理,完成bean实例化,下面开始进入属性装配阶段, 让我们回到AbstractAutowireCapableBeanFactory的doCreateBean方法,

实例化之后,为了处理循环依赖问题,要先把已实例化但未属性装配的bean实例放入到三级缓存中。

 

所谓属性装配,即给bean实例的各种属性赋值(如果遇到属性依赖其他的bean,则先完成所依赖bean的实例化、属性装配、初始化),属性装配完毕后,进入初始化阶段,

在initializeBean方法里,我们可以看到,首先会执行实现了aware接口的方法回调,接着执行beanPostProcessor的before方法,然后执行初始化方法,最后回调beanPostProcessor的after方法。

这一步完成后,我们的refresh方法主要逻辑已经是实现完毕,整个spring ioc容器启动过程也基本完毕了。

 

 

补充:

在AbstractBeanFactory的createBean方法执行完毕后,我们的bean已经完成了实例化、属性装配、初始化,那为什么不直接返回bean实例而要执行这个getObjectForBeanInstance()方法?

这个方法是做什么的呢?

下面我们继续分析下:

这个主要是为了处理FactoryBean的

 

我们看下FactoryBean是什么,这个接口有三个方法,getObject用于返回T类型的实例,

isSingleton方法用来规定 Factory创建的的bean是否是单例。这里通过默认方法定义为单例。

getObjectType用来获取 T getObject()中的返回值 T 的具体类型

public interface FactoryBean<T> {

   String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

   @Nullable

   T getObject() throws Exception;

   @Nullable

   Class<?> getObjectType();

   default boolean isSingleton() {

      return true;

   }

好了,看了上面FactoryBean的介绍,我们可能还是不清楚这个FactoryBean到底是个什么东东?作用是什么?应用场景是什么?

假设我们业务中的一个TestBean实现了FactoryBean接口后,那么通过getBean(beanName)这种方式获取到的bean并不是我们这个TestBean,

而是TestBean所实现的getObject方法的返回值,当我们给beanName加上&前缀时,才会获取到真正的TestBean,

(所以说getBean方法返回的居然是我们实现FactoryBean接口定义的getObject方法返回值)

这就是FactoryBean的作用,那什么情况下可以用到FactoryBean呢?

一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂

如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。

Spring为此提供了一个FactoryBean的工厂类接口,用户可以通过实现该接口的getObject方法来定制实例化Bean的逻辑。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值