2
头图

Spring的两个启动过程具体实现

一、 IOC容器的初始化过程

从图中也可以看出,启动主要包括 BeanDefinition 的 Resource定位、载入和注册三个基本过程:

1. BeanDefinitionResource定位

Resource接口是所有资源的抽象和访问接口,主要有这样几种:
image.png
ResourceLoader接口是资源查找定位策略的统一抽象,具体的资源查找由具体的资源查找实现类给出:

  1. DefaultResourceLoader : ResourceLoader 下的默认实现类
  2. FileSystemResourceLoader:从文件查找资源

    2. BeanDefinition的载入

    这个过程就是把用户定义好的Bean表示成IOC容器内部的数据结构—BeanDefinition,方便容器对Bean进行管理。具体是通过BeanDefinitionReader来完成BeanDefinition在IOC容器中的载入。我们会看到在BeanDefinitionReader接口中有各种loadBeanDefinitions( )方法:

    public interface BeanDefinitionReader {
     
     /**获取BeanDefinition注册表*/
     BeanDefinitionRegistry getRegistry();
     
     ResourceLoader getResourceLoader();
     
     void loadBeanDefinitions(Resource resource) throws BeansException;
     
     void loadBeanDefinitions(Resource... resources) throws BeansException;
     
     void loadBeanDefinitions(String location) throws BeansException;
     
     void loadBeanDefinitions(String... locations) throws BeansException;
    }

    而一般是用XML文件来对BeanDefinition进行定义,因此使用XmlBeanDefinitionReader来完成载入BeanDefinition到IOC容器的过程。

    3. BeanDefinition的注册

    这一步是将上一步已经载入IOC容器的BeanDefinition在IOC容器中进行注册。具体注册是在DefaultListableBeanFactorybeanDefinitionMap中,而其中的注册操作方法,则是由BeanDefinitionRegistry接口来进行操作定义:

    /**
     * @description: BeanDefinition注册表,操作BeanDefinition的几种方法
     * @author: wjw
     * @date: 2022/6/17
     */
    public interface BeanDefinitionRegistry {
    
     /**
      * 向注册表中注册 BeanDefinition
      * @param beanName
      * @param beanDefinition
      */
     void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
    
     /**
      * 利用BeanName查询BeanDefinition
      * @param beanName
      * @return
      * @throws BeansException
      */
     BeanDefinition getBeanDefinition(String beanName) throws BeansException;
    
     /**
      * 判断是否包含指定名称的BeanDefinition
      * @param beanName
      * @return
      */
     boolean containsBeanDefinition(String beanName);
    
     /**
      * 返回注册表中所有的BeanName
      * @return
      */
     String[] getBeanDefinitionNames();
    }

    完成这些步骤后,BeanDefinition就可以被IOC容器所使用了。

    4. BeanDefinition的修改

    此外,IOC容器也提供了一个BeanFactoryProcessor的容器扩展机制,可以在容器实例化对象之前,对注册到容器的BeanDefinition的相应属性进行修改

    二、BeanFactoy容器的实例化过程(依赖注入)

    这个过程实际上是用户第一次调用getBean()来触发的,但是也可以通过在BeanDefinition中控制lazy-init属性来完成对Bean的预实例化。
    事实上,对于Spring中的两种容器,BeanFactory是通过getBean()来触发,而ApplicationContext则是在容器启动后就完成了对所有BeanDefintion的实例化
    我们先来看看在BeanFactoryBean的生命周期:
    image.png
    主要的步骤有:

    1. InstantiationAwareBeanPostProcessorpostProcessBeforeInstantiation()方法

    在实例化Bean前执行该方法。

    2. 实例化Bean

    2.1 getBean()依赖注入的起点

    通过调用getBean()方法,来执行实例化流程。具体代码在AbstractBeanFactory中的 doGetBean()

    protected <T> T doGetBean(final String name, final Object[] args) {
     Object sharedInstance = getSingleton(name);
     if (sharedInstance != null) {
         // 如果是 FactoryBean,则需要调用 FactoryBean#getObject
         return (T) getObjectForBeanInstance(sharedInstance, name);
     }
    
     BeanDefinition beanDefinition = getBeanDefinition(name);
     //生成所需要的Bean,并对Bean初始化进行处理,具体处理在AbstractAutowireCapableBeanFactory中
     Object bean = createBean(name, beanDefinition, args);
     return (T) getObjectForBeanInstance(bean, name);
    }
    
    private Object getObjectForBeanInstance(Object beanInstance, String beanName) {
     if (!(beanInstance instanceof FactoryBean)) {
         return beanInstance;
     }
    
     Object object = getCachedObjectForFactoryBean(beanName);
    
     if (object == null) {
         FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
         object = getObjectFromFactoryBean(factoryBean, beanName);
     }
    
     return object;
    }
    
    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
    
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException;

    我们看到,首先会调用getSingleton()方法,从缓存中获取Bean,处理那些已经被创建过的单例 Bean。防止被重复创建:

  • 如果从缓存中获取了Bean,那么就通过获取的Bean,调用getObjectForBeanInstance()方法,来取得FactoryBean
  • 如果无法从缓存中获取单例Bean,那么调用getBeanDefinition( )createBean()方法,创造对应所需的BeanDefinition 和 Bean。然后利用创建的 Bean来调用getObjectForBeanInstance()方法来获取FactoryBean

    2.2 createBean()生成所需的 Bean

    实际上核心部分在AbstractAutowireCapableBeanFactory类中,createBean()不但生成了所需的 Bean,而且还对Bean初始化进行相应的处理,具体代码如下:

    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
      Object bean = null;
      try {
          // 判断是否返回代理 Bean 对象
          bean = resolveBeforeInstantiation(beanName, beanDefinition);
          if (null != bean) {
              return bean;
          }
          // 实例化 Bean
          bean = createBeanInstance(beanDefinition, beanName, args);
          // 给 Bean 填充属性
          applyPropertyValues(beanName, bean, beanDefinition);
          // 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法
          bean = initializeBean(beanName, bean, beanDefinition);
      } catch (Exception e) {
          throw new BeansException("Instantiation of bean failed", e);
      }
    
      // 注册实现了 DisposableBean 接口的 Bean 对象
      registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
    
      // 判断 SCOPE_SINGLETON、SCOPE_PROTOTYPE
      if (beanDefinition.isSingleton()) {
          registerSingleton(beanName, bean);
      }
      return bean;
    }
    2.2.1 resovleBeforeInstantiation()

    一步一步来看,首先会调用resolveBeforeInstantiation()方法(在源码中,会先判断创建的Bean是否可以实例化,类是否可以通过类装载器载入),如果Bean 配置了PostProcessor,这里返回的会是一个 proxy 代理。
    而且在该方法调用中,如果容器注册实现了InstantiationAwareBeanPostProcessor接口,则在实例化Bean前,将调用这个接口的的postProcessBeforeInstantiation()方法:

    protected Object resolveBeforeInstantiation(String beanName, BeanDefinition beanDefinition) {
      Object bean = applyBeanPostProcessorsBeforeInstantiation(beanDefinition.getBeanClass(), beanName);
      if (null != bean) {
          bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
      }
      return bean;
    }
    
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
      for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
          if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
              Object result = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessBeforeInstantiation(beanClass, beanName);
              if (null != result) return result;
          }
      }
      return null;
    }
    2.2.2 createBeanInstance( )

    其次来到核心的createBeanInstance()方法,用于实例化 Bean(在源码中,会先调用doCreateBean( )来处理一些BeanWrapper、单例Bean等等逻辑后再调用 createBeanInstance()),这里通过调用实例化策略来实例化 Bean:

    protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
      Constructor constructorToUse = null;
      Class<?> beanClass = beanDefinition.getBeanClass();
      Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
      for (Constructor ctor : declaredConstructors) {
          if (null != args && ctor.getParameterTypes().length == args.length) {
              constructorToUse = ctor;
              break;
          }
      }
      return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
    }
    2.2.3 applyPropertyValues()填充属性值

    接下来是给 Bean 填充属性值:

    protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
      try {
          PropertyValues propertyValues = beanDefinition.getPropertyValues();
          for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
    
              String name = propertyValue.getName();
              Object value = propertyValue.getValue();
    
              if (value instanceof BeanReference) {
                  // A 依赖 B,获取 B 的实例化
                  BeanReference beanReference = (BeanReference) value;
                  value = getBean(beanReference.getBeanName());
              }
              // 属性填充
              BeanUtil.setFieldValue(bean, name, value);
          }
      } catch (Exception e) {
          throw new BeansException("Error setting property values:" + beanName);
      }
    }
    2.2.4 执行Bean的初始化initializeBean()
    private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
    
      // invokeAwareMethods
      if (bean instanceof Aware) {
          if (bean instanceof BeanFactoryAware) {
              ((BeanFactoryAware) bean).setBeanFactory(this);
          }
          if (bean instanceof BeanClassLoaderAware) {
              ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
          }
          if (bean instanceof BeanNameAware) {
              ((BeanNameAware) bean).setBeanName(beanName);
          }
      }
    
      // 1. 执行 BeanPostProcessor Before 处理
      Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
    
      // 执行 Bean 对象的初始化方法
      try {
          invokeInitMethods(beanName, wrappedBean, beanDefinition);
      } catch (Exception e) {
          throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);
      }
    
      // 2. 执行 BeanPostProcessor After 处理
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
      return wrappedBean;
    }

    在初始化前,会设置相关的Aware接口,比如BeanFactoryAwareBeanClassLoaderAwareBeanNameAware
    接着调用applyBeanPostProcessorsBeforeInitialization(),执行 BeanPostProcessorpostProcessBeforeInitialization()方法

    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
      Object result = existingBean;
      for (BeanPostProcessor processor : getBeanPostProcessors()) {
          Object current = processor.postProcessBeforeInitialization(result, beanName);
          if (null == current) return result;
          result = current;
      }
      return result;
    }

    然后才来到执行Bean对象的初始化方法:invokeInitMethods()

    private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
      // 1. 实现接口 InitializingBean
      if (bean instanceof InitializingBean) {
          ((InitializingBean) bean).afterPropertiesSet();
      }
    
      // 2. 注解配置 init-method {判断是为了避免二次执行销毁}
      String initMethodName = beanDefinition.getInitMethodName();
      if (StrUtil.isNotEmpty(initMethodName)) {
          Method initMethod = beanDefinition.getBeanClass().getMethod(initMethodName);
          if (null == initMethod) {
              throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
          }
          initMethod.invoke(bean);
      }
    }

    首先调用 InitializingBeanafterPropertiesSet()方法。接着通过init-method属性配置初始化方法。最后再回到initializeBean()方法中,再调用BeanPostProcessorpostProcessAfterInitialization()方法。
    接下来回到最初的createBean()方法里,注册实现DisposableBean接口的 Bean 对象,通过该方法registerDisposableBeanIfNecessary()来实现:

    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
      // 非 Singleton 类型的 Bean 不执行销毁方法
      if (!beanDefinition.isSingleton()) return;
    
      if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
          registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
      }
    }
  • 如果遇到多例,则将准备就绪的Bean传给调用者
  • 如果遇到单例对象,执行销毁方法,这里是将Bean注册进disposableBeans的Map中去,也就是这一段:

    registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));

    利用适配器模式将该Bean注册进存放disposableBeans中去。接下来则是调用DisposableBeandestroy()方法:主要是通过在DisposableBeanAdapter类里面:

    public class DisposableBeanAdapter implements DisposableBean {
    
      private final Object bean;
      private final String beanName;
      private String destroyMethodName;
    
      public DisposableBeanAdapter(Object bean, String beanName, BeanDefinition beanDefinition) {
          this.bean = bean;
          this.beanName = beanName;
          this.destroyMethodName = beanDefinition.getDestroyMethodName();
      }
    
      @Override
      public void destroy() throws Exception {
          /**实现 DisposableBean 接口*/
          if (bean instanceof DisposableBean) {
              ((DisposableBean) bean).destroy();
          }
    
          /**注解配置 destroy-method 的销毁方法*/
          if (StrUtil.isNotEmpty(destroyMethodName) && (bean instanceof DisposableBean && "destroy".equals(this.destroyMethodName))) {
              Method destroyMethod = bean.getClass().getMethod(destroyMethodName);
              if (destroyMethod == null) {
                  throw new BeansException("Couldn't find a destroy method named '" + destroyMethodName + "' on bean with name '" + beanName + "'");
              }
              destroyMethod.invoke(bean);
          }
      }
    }

    主要有两个步骤,首先调用DisposableBeandestory()方法,然后再通过destory-method配置属性的销毁方法。到此,完成Bean的生命周期

    Bean 生命周期接口相关的配置

  1. 可以通过 <Bean> 的init-methoddestroy-method属性的配置方式为Bean指定初始化和销毁方法,这种方式对Bean生命周期的控制效果相当于实现InitializingBeanDisposableBean接口的效果
  2. BeanFactoryAware接口让Bean感知容器,BeanNameAware接口让Bean获得配置文件中对应的配置名称。

    Spring两个启动过程的大体步骤


归思君
1.2k 声望209 粉丝

阿里云社区专家博主,华为云社区云享专家,一个会点前端的java工程师。