文章篇幅较长,会针对于生命周期中的各个时期进行实例演示以及源码讲解。

Spring Bean作用域_创建对象

Spring组织架构

在Spring中,Bean生命周期从流程上来分析大概可以得到上面的图片,各个环节涉及到的对象大概如下图:

Spring Bean作用域_生命周期_02

Spring Bean生命周期

下面我们对每一个环节来进行具体分析:

读取Bean定义

元信息读取

我们要创建一个Bean,首先第一步就要知道Bean的元信息,在Spring中,主要提供了四种读取Bean元信息的方式,分别是Xml、Properties、Groovy和Annotated。读取方式都特别简单:

public class ParseBeanDefinitionDemo {

  @Bean
  public String str() {
    return "annotated source";
  }

  public static void main(String[] args) {
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

    // xml方式读取
    XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(factory);
    xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/xml-bean-definition-reader.xml");

    // properties方式读取
    PropertiesBeanDefinitionReader propertiesBeanDefinitionReader = new PropertiesBeanDefinitionReader(factory);
    propertiesBeanDefinitionReader.loadBeanDefinitions("/META-INF/properties-bean-definition-reader.properties");

    // groovy方式读取
    GroovyBeanDefinitionReader groovyBeanDefinitionReader = new GroovyBeanDefinitionReader(factory);
    groovyBeanDefinitionReader.loadBeanDefinitions("/META-INF/groovy-bean-definition-reader.groovy");

    // 注解方式读取
    AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(factory);
    annotatedBeanDefinitionReader.register(ParseBeanDefinitionDemo.class);
  }
}

我们来简单看一下他的UML类图:

Spring Bean作用域_生命周期_03

image-20230422090847726

从上图我们可以看到,Xml、Properties、Groovy的读取方式都继承了AbstractBeanDefinitionReader,而使用注解方式的没有继承而是有单独的实现,其实这个也很好理解,因为前三个都是读取的外部化文件进行解析获取,所以有统一读取的规范,而注解是直接嵌插在Java代码中的,所以与前三个读取方式会有所不同。

Xml注册中的语法我们已经很熟悉,而对于Properties和Groovy的我们可以参考各个读取实现对象上面的注释,而一般情况我们也不会用到这两种读取方式。

Spring Bean作用域_生命周期_04

image-20230422091831812

元信息注册

读取到Bean得元信息之后就需要把Bean的元信息注册到BeanFactory中,而Bean主要是使用BeanDefinitionRegistry#registerBeanDefinition()方法进行注册。

Bean元信息注册有个工具类BeanDefinitionReaderUtils,我们来看一下他注册BeanDefinition的方法:

BeanDefinitionReaderUtils:BeanDefinitionReaderUtils():

image-20230422093421425

一个BeanFactory的实例对象通常还是一个Bean元信息的注册对象,所以上面的BeanDefinitionRegistry通常就是一个IOC容器对象,我们拿DefaultListableBeanFactory的容器对象来看(他是IOC容器,但是本身也是是一个BeanDefinitionRegistry

image-20230422093013200

获取Bean实例

如果说读取Bean定义为Bean实例化的准备阶段,那么获取Bean实例阶段就是创建Bean对象以及管理Bean生命周期中最重要的阶段。他的核心代码主要是在AbstractBeanFactory#doGetBean()方法中,接下来我们的所有步骤都是围绕着这个方法展开讲解的。

我们先来看看doGetBean方法中针对于 创建对象 过程中几个比较重要的关键步骤:

protected <T> T doGetBean(
  String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
  throws BeansException {
  // .....  

  try {
    // 合并并检查Bean定义信息
    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    checkMergedBeanDefinition(mbd, beanName, args);

    // Create bean instance.
    // 创建单例对象
    if (mbd.isSingleton()) {
      // 获得单例对象
      sharedInstance = getSingleton(beanName, () -> {
        try {
          return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
          destroySingleton(beanName);
          throw ex;
        }
      });
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }

    // 创建原型对象
    else if (mbd.isPrototype()) {
      // It's a prototype -> create a new instance.
      Object prototypeInstance = null;
      try {
        beforePrototypeCreation(beanName);
        // 获得原型对象
        prototypeInstance = createBean(beanName, mbd, args);
      }
      finally {
        afterPrototypeCreation(beanName);
      }
      bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    }

    // .....
    return (T) bean;
  }

上面主要包含两个步骤:1、合并Bean得元信息定义;2、校验单例或者原型模式创建对象,我们逐一进行分析。

合并Bean定义

为什么需要合并Bean定义呢?因为在xml中可能会存在如下定义(也就需要是将user中的定义合并到supperUser中,具体怎么使用这里就不演示了):

<bean name="user" class="com.phshi.entity.User">
  <property name="name" value="zhansan"/>
  <property name="sex" value="1"/>
</bean>

<!-- parent情况 -->
<bean name="supperUser" class="com.phshi.entity.SupperUser" parent="user">
  <property name="specialAbilities" value="飞行"/>
</bean>

从上面doGetBean的方法中我们可以看到,合并的入口是getMergedLocalBeanDefinition()方法,接下来我们来看一下合并过程的具体逻辑:

AbstractBeanFactory#getMergedLocalBeanDefinition(String beanName)

// 存储合并过后的Bean定义信息的RootBeanDefinition集合
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
  // 通过名称取出Bean得定义信息
  RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
  // 如果不是空并且校验是否需要重新合并
  if (mbd != null && !mbd.stale) {
    return mbd;
  }
  // 合并逻辑    getBeanDefinition(beanName)就是获取未合并之前的bean定义
  return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

创建合并过程:

AbstractBeanFactory#getMergedBeanDefinitiongetMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd):

protected RootBeanDefinition getMergedBeanDefinition(
  String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
  throws BeanDefinitionStoreException {

  synchronized (this.mergedBeanDefinitions) {
    // 记录需要返回的RootBeanDefinition
    RootBeanDefinition mbd = null;
    RootBeanDefinition previous = null;

    // 再校验一次状态
    if (mbd == null || mbd.stale) {
      previous = mbd;
      // 校验是否包含parentName  不包含就不用合并 包含才需要合并
      if (bd.getParentName() == null) {
        if (bd instanceof RootBeanDefinition) {
          mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
        }
        else {
          mbd = new RootBeanDefinition(bd);
        }
      }
      else {
        // 合并逻辑
        BeanDefinition pbd;
        try {
          String parentBeanName = transformedBeanName(bd.getParentName());
          if (!beanName.equals(parentBeanName)) {
            // 取出parentBean的RootBeanDefinition
            pbd = getMergedBeanDefinition(parentBeanName);
          }
          else {
            // 如果beanName和parentBeanName相同,则去ParentBeanFactory中获取beanDefinition进行合并
            BeanFactory parent = getParentBeanFactory();
            if (parent instanceof ConfigurableBeanFactory) {
              pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
            }
            else {
              throw new NoSuchBeanDefinitionException(parentBeanName,
                                                      "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                                      "': cannot be resolved without a ConfigurableBeanFactory parent");
            }
          }
        }
        catch (NoSuchBeanDefinitionException ex) {
          throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                                                 "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
        }
        // Deep copy with overridden values.
        mbd = new RootBeanDefinition(pbd);
        // 具体的合并逻辑  具体就是一些复制的逻辑,这里就不展开看了
        mbd.overrideFrom(bd);
      }
      // ....
      return mbd;
    }
  }

在Bean的定义信息合并完成之后,我们就会获得RootBeanDefinition,接下来,我们就会使用这个RootBeanDefinition进行创建对象。

创建对象实例

在前文代码中我们可以看到,在doGetBean()方法中创建对象会根据作用域的不同来进行创建,在但是都会执行一个核心方法createBean(),在这里我们就拿单例作用域来进行讲解。

我们可以看到单例创建对象的方法主要如下:

if (mbd.isSingleton()) {
  // 注意后面是一个ObjectFactory的匿名内部类,创建对象的逻辑主要就是集中在createBean中
  sharedInstance = getSingleton(beanName, () -> {
    try {
      return createBean(beanName, mbd, args);
    }
    catch (BeansException ex) {
      destroySingleton(beanName);
      throw ex;
    }
  });
  bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

我们先来简单看一下getSingleton()方法:

getSingleton(String beanName, ObjectFactory<?> singletonFactory):

// singleton对象的缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
  synchronized (this.singletonObjects) {
    // 先从singletonObjects对象中获取
    Object singletonObject = this.singletonObjects.get(beanName);
    //  singletonObjects对象中未取到才进行对象创建
    if (singletonObject == null) {
      // 可以作为循环引用的校验
      beforeSingletonCreation(beanName);
      try {
        // 核心:调用匿名函数创建对象
        singletonObject = singletonFactory.getObject();
      } catch (IllegalStateException ex) {
        singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
          throw ex;
        }
      } catch (BeanCreationException ex) {
        afterSingletonCreation(beanName);
      }
      if (newSingleton) {
        // 添加到singletonObjects中
        addSingleton(beanName, singletonObject);
      }
    }
    return singletonObject;
  }
}

生命周期中最核心的方法入口:

下面我们来看看创建对象的核心方法createBean:

createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args):

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
  throws BeanCreationException {
  RootBeanDefinition mbdToUse = mbd;
  // 1、获得Class对象,就是指定ClassLoader进行加载
  Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
  if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
    mbdToUse = new RootBeanDefinition(mbd);
    mbdToUse.setBeanClass(resolvedClass);
  }

  // 2、进行方法重写
  mbdToUse.prepareMethodOverrides();

  // 3、执行实例化前的后置处理
  Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
  if (bean != null) {
    return bean;
  }

  // 4、创建实例对象
  Object beanInstance = doCreateBean(beanName, mbdToUse, args);
  return beanInstance;
}

获得Class对象

创建对象前最重要的一步就是使用ClassLoader去加载从而获得Class对象,而在Spring中,使用ClassLoader加载获得Class对象主要是集中在createBean方法中标记的第一步resolveBeanClass这个方法中。

resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch):

protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
  throws CannotLoadBeanClassException {
  // 校验对象类型是否是Class类型   this.beanClass instanceof Class
  // this.beanClass是一个Object对象,比如xml配置的一般一开始对象类型都是String的
  if (mbd.hasBeanClass()) {
    return mbd.getBeanClass();
  }
  // ...
  return doResolveBeanClass(mbd, typesToMatch);
}

private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
  throws ClassNotFoundException {

  // 使用两个加载器的区别: 
  // beanClassLoader会使上一步的this.beanClass变成Class对象从而不会再进行重新加载
  // dynamicLoader不会变this.beanClass从而每次实例化都需要进行重新加载class
  ClassLoader beanClassLoader = getBeanClassLoader();
  ClassLoader dynamicLoader = beanClassLoader;
  boolean freshResolve = false;

  if (!ObjectUtils.isEmpty(typesToMatch)) {
    // 使用临时类加载器
    ClassLoader tempClassLoader = getTempClassLoader();
  }

  String className = mbd.getBeanClassName();
  // 使用动态加载器进行加载
  if (className != null) {
    Object evaluated = evaluateBeanDefinitionString(className, mbd);
    if (!className.equals(evaluated)) {
      // A dynamically resolved expression, supported as of 4.2...
      if (evaluated instanceof Class) {
        return (Class<?>) evaluated;
      }
      else if (evaluated instanceof String) {
        className = (String) evaluated;
        freshResolve = true;
      }
      else {
        throw new IllegalStateException("Invalid class name expression result: " + evaluated);
      }
    }
    if (freshResolve) {
      if (dynamicLoader != null) {
        try {
          return dynamicLoader.loadClass(className);
        }
        catch (ClassNotFoundException ex) {
          if (logger.isTraceEnabled()) {
            logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
          }
        }
      }
      return ClassUtils.forName(className, dynamicLoader);
    }
  }

  // 加载存入缓存
  return mbd.resolveBeanClass(beanClassLoader);
}

public Class<?> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {
  String className = getBeanClassName();
  if (className == null) {
    return null;
  }
  Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
  // 存储到了beanClass中
  this.beanClass = resolvedClass;
  return resolvedClass;
}

createBean方法中的第二步prepareMethodOverrides主要是对bean标签中配置的lookup-method以及属性replaced-method进行重写覆盖。代码比较少也比较简单,这里就不进行讲解。

执行实例化前后置处理器

该步骤存在的主要意义是借助BeanPostProcessors给我们想要创建的Bean一个返回代理对象而不是目标bean实例的机会。该方式的核心就是InstantiationAwareBeanPostProcessor接口。他也是Bean生命周期中一个非常重要的接口,提供了实例化前、实例化后以及属性赋值相关的处理方法。

  • • 下面我们先来进行简单演示使用方式:
public class BeanPostProcessorsBeforeInstantiationDemo implements InstantiationAwareBeanPostProcessor {

  @Bean(name="str")
  public String str(){
    return "这是我原来注册是值";
  }

  public static void main(String[] args) {
    AnnotationConfigApplicationContext factory = new AnnotationConfigApplicationContext();
    // 注册后置处理器
    factory.addBeanFactoryPostProcessor(process->process.addBeanPostProcessor(new BeanPostProcessorsBeforeInstantiationDemo()));
    factory.register(BeanPostProcessorsBeforeInstantiationDemo.class);
    factory.refresh();

    // 打印:str = 我是改变后的值
    System.out.println("str = " + factory.getBean(String.class));
    factory.close();
  }

  /**
   * 初始化方法前的后置处理
   * 如果返回不是空则对象为现在返回的对象,如果为空则继续进行下面的创建
   */
  @Override
  public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    if (ObjectUtils.nullSafeEquals(beanName,"str") && String.class.equals(beanClass)) {
      return "我是改变后的值";
    }
    return null;
  }
}
  • • 下面我们来看看源码

resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd):

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
  Object bean = null;
  if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      Class<?> targetType = determineTargetType(beanName, mbd);
      if (targetType != null) {
        // 执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法
        bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
        if (bean != null) {
          // 如果不为空的则直接执行初始化的后置处理器
          bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        }
      }
    }
    mbd.beforeInstantiationResolved = (bean != null);
  }
  return bean;
}

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
  // 遍历所有的BeanPostProcessor并筛选出InstantiationAwareBeanPostProcessor
  for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
      InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
      // 执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法
      Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
      if (result != null) {
        return result;
      }
    }
  }
  return null;
}

上面的代码少并且超级简单,这里就不在过多概述了。

InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()的价值就在于拦截指定的Bean然后可以返回一个我们想要的对象或者是代理对象,在Spring中AOP动态代理就是接这个方式进行实现的,具体详情可以参考AbstractAutoProxyCreator

实例化

在执行完Bean的实例化前后置处理器之后,便要开始进行实例化了,首先我们先来看一下doCreateBean方法中的主要功能。

doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args):

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
  throws BeanCreationException {
  // Bean实例的包装对象
  BeanWrapper instanceWrapper = null;

  // 1、创建对象实例
  instanceWrapper = createBeanInstance(beanName, mbd, args);

  // 2、执行后置处理合并Bean得定义信息
  applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
  
  // 中间还有一个执行SmartInstantiationAwareBeanPostProcessor处理的地方,但是Spring标注为了专用接口,为框架内部解决循环引用使用,这里就忽略了

  // 3、对bean的属性进行填充
  populateBean(beanName, mbd, instanceWrapper);
  
  // 4、执行bean的初始化方法
  exposedObject = initializeBean(beanName, exposedObject, mbd);

  // 5、注册Bean的信息方便Bean销毁时候使用
  registerDisposableBeanIfNecessary(beanName, bean, mbd);
  return exposedObject;
}

首先来看第一步,创建实例对象,在Spring中,如果不规定创建对象的方法的话,主要是会使用了CGLIB或者是JDK动态代理两种方式对对象进行实例化。整体来看这个创建对象的过程还是比较复杂的,对其我们就不深入追究了,我们就简单来看一下createBeanInstance方法。

createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args):

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
  // 获得Class对象
  Class<?> beanClass = resolveBeanClass(mbd, beanName);

  // 使用Supplier创建对象
  Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
  if (instanceSupplier != null) {
    return obtainFromSupplier(instanceSupplier, beanName);
  }

  // 使用工厂方法创建对象
  if (mbd.getFactoryMethodName() != null) {
    return instantiateUsingFactoryMethod(beanName, mbd, args);
  }

  // 使用有参构造方法创建  
  Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
  if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
      mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
    return autowireConstructor(beanName, mbd, ctors, args);
  }

  // 使用默认无参构造方法创建 
  ctors = mbd.getPreferredConstructors();
  if (ctors != null) {
    return autowireConstructor(beanName, mbd, ctors, null);
  }

  // 通过CGlib或者JDK动态代理创建对象
  return instantiateBean(beanName, mbd);
}

执行Bean定义信息处理器

上一步结束,我们的对象就已经被创建完成了,当然,现在的他还只是一个最原生的对象,当然,现在他可以被使用,只不过他还未进行属性赋值,也就是说,他的所有属性现在都还是空的。所以按照流程来讲,下一步我们就是对上一步创建出来的对象进行赋值。

实际上,在对对象赋值之前还有一个步骤要进行处理。Spring留了一步,允许我们在对属性赋值前有一个机会去修改Bean的定义信息。修改方式Spring也是使用了BeanPostProcessor这种后置处理的方式。Spring中提供了一个BeanPostProcessor的子类MergedBeanDefinitionPostProcessor专门用来修改或者是重新重制Bean得一些定义信息。

我们先来演示一下他的使用方式:

使用方式:

public class MergedBeanDefinitionPostProcessorDemo implements MergedBeanDefinitionPostProcessor {

  @Bean
  public User user() {
    User user = new User();
    user.setName("lisi");
    user.setSex(0);
    return user;
  }

  public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    // 使用了AnnotationConfigApplicationContext可以不用手动注册PostProcessor
    //        applicationContext.addBeanFactoryPostProcessor(process -> process.addBeanPostProcessor(new MergedBeanDefinitionPostProcessorDemo()));
    applicationContext.register(MergedBeanDefinitionPostProcessorDemo.class);
    applicationContext.refresh();

    User user = applicationContext.getBean(User.class);
    // 打印的:name='王武', sex=1 而不是 name='lisi', sex=0
    System.out.println("user = " + user);
    applicationContext.close();
  }

  @Override
  public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    if (ObjectUtils.nullSafeEquals(beanName, "user") && User.class.equals(beanType)) {
      MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
      propertyValues.add("name", "王武");
      propertyValues.add("sex", 1);
    }
  }
}

我们再来看看他在Spring中的源码:

源码:

applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName):

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
  for (BeanPostProcessor bp : getBeanPostProcessors()) {
    // 校验Process是否是MergedBeanDefinitionPostProcessor类型
    if (bp instanceof MergedBeanDefinitionPostProcessor) {
      MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
      bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
    }
  }
}

代码也很简单,遍历所有的process方法,获取到MergedBeanDefinitionPostProcessor类型的处理器并执行postProcessMergedBeanDefinition方法。

MergedBeanDefinitionPostProcessor执行的代码虽然简单,但是在Spring中却扮演着重要的角色,我们常常用到的@Autowired或者是@Resource注入的属性就是在这里被扫描到并存储起来用于后面注入的,这里就不展开讲了,后面有机会我们在来讲解相关知识。

填充Bean属性

当我们最后一次允许修改Bean定义信息之后,那么相当于我们Bean得定义信息就已经确认好了,接下来我们就可以放心的进行属性的填充。属性填充随着填充方式多样,所以代码也比较多,主要集中在AbstractAutowireCapableBeanFactory#populateBean()方法中,我们先整体来看一下这个方法。

populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw):

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
  // 1、使用InstantiationAwareBeanPostProcessor进行直接注入,返回false跳过后续自动注入过程
  if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
          return;
        }
      }
    }
  }

  PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
  int resolvedAutowireMode = mbd.getResolvedAutowireMode();
  // 2、校验注入模式是否是自动注入
  if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    // 2.1、按照名称自动注入
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
      autowireByName(beanName, mbd, bw, newPvs);
    }
    // 2.2、按照类型自动注入
    if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      autowireByType(beanName, mbd, bw, newPvs);
    }
    pvs = newPvs;
  }

  boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
  boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

  PropertyDescriptor[] filteredPds = null;
  if (hasInstAwareBpps) {
    if (pvs == null) {
      pvs = mbd.getPropertyValues();
    }
    // 3、使用InstantiationAwareBeanPostProcessor中提供的方法进行注入
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
        if (pvsToUse == null) {
          if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
          }
          // 该方法已经设置为废弃,被postProcessProperties代替
          pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
          if (pvsToUse == null) {
            return;
          }
        }
        pvs = pvsToUse;
      }
    }
  }

  // 4、属性设置  上面三步其实都只是将属性值设置到PropertyValues中,这步才将值进行赋值到对象上
  applyPropertyValues(beanName, mbd, bw, pvs);
}

从上面的代码分析中我们大概可以看出注入大概分为四种方式:

  • • 通过实例化后置处理器InstantiationAwareBeanPostProcessorpostProcessAfterInstantiation方法进行直接注入(该注入方式可以跳过后面的自动注入)
  • • 通过类型或者名称自动注入
  • • 通过InstantiationAwareBeanPostProcessorpostProcessProperties方法或者是postProcessPropertyValues方法进行注入(后面的方法已经弃用)
  • • 属性值设置方式(包含基本类型注入以及引用类型注入,其实上面三步是将值设置到PropertyValues中,而这步是将PropertyValues的值设置到对象中)

下面我们一个一个的分析上面四种注入方式:

实例化后置处理器注入

首先,我们先来看看实例化后置处理器注入的使用方式。

使用方式:

public class PostProcessAfterInstantiationDemo implements InstantiationAwareBeanPostProcessor {

  @Bean
  public User user() {
    User user = new User();
    user.setName("lisi");
    user.setSex(0);
    return user;
  }

  public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    // 使用了AnnotationConfigApplicationContext可以不用手动注册PostProcessor
    // applicationContext.addBeanFactoryPostProcessor(process -> process.addBeanPostProcessor(new PostProcessAfterInstantiationDemo()));
    applicationContext.register(PostProcessAfterInstantiationDemo.class);
    applicationContext.refresh();

    User user = applicationContext.getBean(User.class);
    // 打印的:name='王武', sex=1 而不是 name='lisi', sex=0
    System.out.println("user = " + user);
    applicationContext.close();
  }

  @Override
  public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    if (ObjectUtils.nullSafeEquals(beanName, "user") && User.class.equals(bean.getClass())) {
      User user = (User) bean;
      // 进行属性赋值替换
      user.setName("王武");
      user.setSex(1);
      return false;
    }
    return true;
  }
}

对于源码也比较简单,就是populateBean方法中的第一步,这里就不再单独列出来一次了。

通过类型或名称自动注入

这种自动注入的方式主要针对于的是引用的数据类型,基本类型是不支持自动注入的。

通过类型注入通常是使用xml配置的,使用起来也比较简单,我们就不进行演示了。我们直接来看看注入的实现原理吧!

通过名称注入:

autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs):

protected void autowireByName(
  String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

  String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
  // 遍历所有的属性
  for (String propertyName : propertyNames) {
    // 使用名称去BeanFactory容器中查询是否存在这个Bean
    if (containsBean(propertyName)) {
      // 通过Bean名称去容器中获取对象
      Object bean = getBean(propertyName);
      // 设置值
      pvs.add(propertyName, bean);
      registerDependentBean(propertyName, beanName);
    }
  }
}

通过名称注入就比较简单了,校验IOC容器中是否存在指定名称的Bean,如果存在取出来设置进去就ok了。

通过类型注入:

autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs):

protected void autowireByType(
  String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

  TypeConverter converter = getCustomTypeConverter();
  if (converter == null) {
    converter = bw;
  }

  Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
  String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
  // 遍历所有的属性
  for (String propertyName : propertyNames) {
    try {
      PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
      if (Object.class != pd.getPropertyType()) {
        MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
        boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
        DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
        // 核心就是这里的按照类型进行依赖查找  该方法在前面的依赖注入方法进行了详细讲解
        Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
        // 查询到则设置值
        if (autowiredArgument != null) {
          pvs.add(propertyName, autowiredArgument);
        }
        for (String autowiredBeanName : autowiredBeanNames) {
          registerDependentBean(autowiredBeanName, beanName);
        }
        autowiredBeanNames.clear();
      }
    }
    catch (BeansException ex) {
      throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
    }
  }
}

上面代码看着虽然多,但是最核心其实就是resolveDependency方法,该方法会按照类型去查找对应的Bean对象,该方法在前面章节 Spring依赖注入(二) - 注入过程 进行了详细讲解。

postProcessProperties方法

该方式注入可以算是注入方式的一个扩展,他支持了第三方或者些复杂的方式注入,比如@Autowired或者是@Resource注入都是在这一步完成的。下面我们先来看一下他的使用方式。

使用方式:

这里只演示postProcessProperties方法,postProcessPropertyValues方法使用方式和这个类似,就不进行演示了

public class PostProcessPropertiesDemo implements InstantiationAwareBeanPostProcessor {

  @Bean
  public User user() {
    User user = new User();
    user.setName("lisi");
    user.setSex(0);
    return user;
  }

  public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    // 使用了AnnotationConfigApplicationContext可以不用手动注册PostProcessor
    // applicationContext.addBeanFactoryPostProcessor(process -> process.addBeanPostProcessor(new PostProcessPropertiesDemo()));
    applicationContext.register(PostProcessPropertiesDemo.class);
    applicationContext.refresh();

    User user = applicationContext.getBean(User.class);
    // 打印的:name='王武', sex=1 而不是 name='lisi', sex=0
    System.out.println("user = " + user);
    applicationContext.close();
  }

  @Override
  public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    if (ObjectUtils.nullSafeEquals(beanName, "user") && User.class.equals(bean.getClass())) {
      MutablePropertyValues propertyValues = new MutablePropertyValues();
      propertyValues.addPropertyValue("name","王武");
      propertyValues.addPropertyValue("sex",1);
      return propertyValues;
    }
    return pvs;
  }
}

具体这块的源代码实现也很简单,这里也就不单独列出来了。

属性值设置

这一步可以说是整个属性填充最重要的一步,前面三步其实相当于将属性的值都设置到了PropertyValues中,这一步中会将PropertyValues中取出来填充到我们实例化处理的对象中。

applyPropertyValues方法前面的步骤其实都是为了处理类型转化,比如我们在xml里面配置的是String类型,但是我们最终却可以注入到Integer类型中其实就是在这一步中进行了数据转化,

该方法大概可以分为三个步骤:

  • • 输入对象类型的转化
  • • 通过可写方法(set方法)的入参类型进行转化
  • • 给对象赋值

我们先来简单的看一下他的代码:

applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs):

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {


  MutablePropertyValues mpvs = null;
  List<PropertyValue> original;

  if (pvs instanceof MutablePropertyValues) {
    mpvs = (MutablePropertyValues) pvs;
    // 如果已经完成了类型转化的话可以进行直接赋值。 在下文转化完了之后修改了状态为转化完成
    if (mpvs.isConverted()) {
      try {
        bw.setPropertyValues(mpvs);
        return;
      }
      catch (BeansException ex) {
        throw new BeanCreationException(
          mbd.getResourceDescription(), beanName, "Error setting property values", ex);
      }
    }
    original = mpvs.getPropertyValueList();
  }
  else {
    original = Arrays.asList(pvs.getPropertyValues());
  }

  // 获取自定义类型转化器(一般都是null)
  TypeConverter converter = getCustomTypeConverter();
  if (converter == null) {
    converter = bw;
  }
  // 获得类型解析器
  BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

  // 需要将填入对象进行深拷贝,以免出现问题
  List<PropertyValue> deepCopy = new ArrayList<>(original.size());
  boolean resolveNecessary = false;
  for (PropertyValue pv : original) {
    // 校验是否需要转化
    if (pv.isConverted()) {
      deepCopy.add(pv);
    }
    else {
      // 获得转化的属性名与属性值
      String propertyName = pv.getName();
      Object originalValue = pv.getValue();

      // 进行类型转化
      Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
      Object convertedValue = resolvedValue;

      // 校验转化的字段是否可写
      boolean convertible = bw.isWritableProperty(propertyName) &&
        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
      if (convertible) {
        // 再使用set方法再进行一次类型转化  String转化为Integer就是在这处理的
        convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
      }
    }
  }

  if (mpvs != null && !resolveNecessary) {
    // 设置完成了类型转化
    mpvs.setConverted();
  }

  // 设置属性 最终其实执行writeMethod.invoke(getWrappedInstance(), value)反射赋值
  bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
  • • 1、resolveValueIfNecessary(Object argName, @Nullable Object value):

该方法通过各种传入数据不同类型判断然后走不通的数据转化方法(具体不列出转化方式,具体可以去对象BeanDefinitionValueResolver#resolveValueIfNecessary()中查看该方法):

public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
  if (value instanceof RuntimeBeanReference) {

  }
  else if (value instanceof RuntimeBeanNameReference) {

  }
  else if (value instanceof BeanDefinitionHolder) {

  }
  else if (value instanceof BeanDefinition) {

  }
  else if (value instanceof DependencyDescriptor) {

  }
  else if (value instanceof ManagedArray) {

  }
  else if (value instanceof ManagedList) {

  }
  else if (value instanceof ManagedSet) {

  }
  else if (value instanceof ManagedMap) {

  }
  else if (value instanceof ManagedProperties) {

  }
  else if (value instanceof TypedStringValue) {

  }
  else if (value instanceof NullBean) {

  }
  else {
    return evaluate(value);
  }
}

protected Object evaluate(@Nullable Object value) {
  if (value instanceof String) {

  }
  else if (value instanceof String[]) {

  }
  else {
    return value;
  }
}

上一步结束只是对对象类型进行了一个简单的转化,并不会将String转化为Integer或者是将资源路径转化资源对象。而这个转化是在下一步convertForProperty中进行的。

  • • 2、convertForProperty(@Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter):
@Nullable
private Object convertForProperty(
  @Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {

  if (converter instanceof BeanWrapperImpl) {
    return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
  }
  else {
    // 获得可写方法
    PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
    MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
    // 类型转化
    return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
  }
}

@Nullable
public Object convertForProperty(@Nullable Object value, String propertyName) throws TypeMismatchException {
  CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults();
  // 获得propertyName属性相关的属性类型信息,包括写(set)和读(get)方法
  PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName);
  if (pd == null) {
    throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
                                       "No property '" + propertyName + "' found");
  }
  // 获得设置的对象的具体类型
  TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
  if (td == null) {
    td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd)));
  }
  // 类型转化
  return convertForProperty(propertyName, null, value, td);
}
  • • 3、最后的bw.setPropertyValues方法便是给对象进行属性赋值

这一步方法嵌套比较深看着比较复杂,但是整体来看逻辑很简单,就是拿到可写方法(set方法),然后使用writeMethod.invoke(getWrappedInstance(), value)放射进行复制,详情可以自己去追踪源码查看。

Bean的属性赋值整体来说很复杂,尤其是类型转化,可以说是整个生命周期中最复杂的步骤了,而对于类型转化TypeDescriptor也只是随便说了几句,因为它本身就是一个很复杂的东西,不是这里讲解的重点,后面如果有机会我们会进行相关的讲解。

执行Bean初始化方法

Bean的属性赋值结束,那么接下来的就都比较轻松了。Bean实例化好并且属性赋值完毕,下一步就是开始执行Bean相关的初始化方法。在源码中,这一块代码是在AbstractAutowireCapableBeanFactory.initializeBean(),在这一步中,我们可以划分为如下几个步骤:

  • • 执行Aware接口
  • • 执行BeanPostProcessor的初始化前的后置处理器
  • • 执行InitializingBeanafterPropertiesSet方法
  • • 执行xml中配置的init-method方法
  • • 执行BeanPostProcessor的初始化后的后置处理器

首先,我们依旧是先整体来看一下这一块的代码:

initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd):

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {

  // 执行Aware接口方法
  invokeAwareMethods(beanName, bean);

  // 执行 BeanPostProcessor 的初始化前的后置处理器
  wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

  // 执行初始化方法
  invokeInitMethods(beanName, wrappedBean, mbd);

  // 执行 BeanPostProcessor 的初始化后的后置处理器
  wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  return wrappedBean;
}

执行Aware接口

首先我们来回顾一下Aware接口有哪些:

接口名称

描述

BeanFactoryAware

获取 IoC 容器 - BeanFactory

ApplicationContextAware

获取 Spring 应用上下文 - ApplicationContext 对象

EnvironmentAware

获取 Environment 对象

ResourceLoaderAware

获取资源加载器 对象 - ResourceLoader

BeanClassLoaderAware

获取加载当前 Bean Class 的 ClassLoader

BeanNameAware

获取当前 Bean 的名称

MessageSourceAware

获取 MessageSource 对象,用于 Spring 国际化

ApplicationEventPublisherAware

获取 ApplicationEventPublishAware 对象,用于 Spring 事件

EmbeddedValueResolverAware

获取 StringValueResolver 对象,用于占位符处理

Aware相关的接口主要就是上面几个,我们在 Spring依赖注入(一) - 注入方式 章节讲解过,页演示了怎么使用,这里就再演示了,记不得的可以回去回顾一下。

我们下面还是从源码看是看吧:

invokeAwareMethods(String beanName, Object bean):

private void invokeAwareMethods(String beanName, Object bean) {
  if (bean instanceof Aware) {
    // 执行 BeanNameAware 接口方法
    if (bean instanceof BeanNameAware) {
      ((BeanNameAware) bean).setBeanName(beanName);
    }
    // 执行 BeanClassLoaderAware 接口方法
    if (bean instanceof BeanClassLoaderAware) {
      ClassLoader bcl = getBeanClassLoader();
      if (bcl != null) {
        ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
      }
    }
    // 执行 BeanFactoryAware 接口方法
    if (bean instanceof BeanFactoryAware) {
      ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
    }
  }
}

从上面方法中我们9个Aware接口却只执行了3个,这是为什么呢?其实原因很简单,现在当前对象是BeanFactory,说具体一点是DefaultListableBeanFactory,而在这九个Aware接口中他能拿到的数据也只有这三个,另外6个都是依赖于ApplicationContext的,但是DefaultListableBeanFactory又拿不到ApplicationContext的信息,所以其他九个就不在这里执行。

那么另外6个不在这里执行在哪执行呢?由于是执行Aware接口,这里我们就提前说明,其实另外六个是在初始化前的后置处理器中进行,这里我们先来提前看一下ApplicationContextAwareProcessor这个处理器中的初始化前的后置处理方法。

class ApplicationContextAwareProcessor implements BeanPostProcessor {

  private final ConfigurableApplicationContext applicationContext;

  private final StringValueResolver embeddedValueResolver;

  @Override
  @Nullable
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // 如果不属于这些接口则返回
    if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
          bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
          bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
      return bean;
    }

    // 属于则设置对应值
    invokeAwareInterfaces(bean);
    return bean;
  }

  private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof EnvironmentAware) {
      ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
    }
    if (bean instanceof EmbeddedValueResolverAware) {
      ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
    }
    if (bean instanceof ResourceLoaderAware) {
      ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
    }
    if (bean instanceof ApplicationEventPublisherAware) {
      ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
    }
    if (bean instanceof MessageSourceAware) {
      ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
    }
    if (bean instanceof ApplicationContextAware) {
      ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    }
  }
}

执行初始化前的后置处理器

在上一步中我们也看到了初始化前后置处理器的一种使用方式,而初始化前的后置处理器执行源码也非常简单:

applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName):

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
  throws BeansException {

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

虽然上一步我们看到了关于applicationContext相关的Aware接口在初始化前的后置处理器中执行了,但是他在Spring中的使用也不仅仅如此,比如我们在@PostConstruct进行初始化或者是@PreDestroy进行销毁也是采用这种方式去实现的,具体实现的可以去InitDestroyAnnotationBeanPostProcessor对象中进行查看。

执行初始化方法

在 Spring Bean基础 中我们讲到过,对象的初始化主要有三种方式:

  • • @PostConstruct注解
  • • 实现 InitializingBean 接口的 afterPropertiesSet() 方法
  • • 使用@Bean或者xml中initMethod定义的初始化方法

而那时候我们也说明了他们三个执行的先后顺序是:@PostConstruct -> InitializingBean -> @Bean

我们先来用一个案例来进行说明:

public class User implements InitializingBean {
  private String name;
  private Integer sex;

  // .... get、set、toString方法

  @PostConstruct
  public void init() {
    System.out.println("@PostConstruct初始化执行");
  }

  @Override
  public void afterPropertiesSet() throws Exception {
    System.out.println("InitializingBean中的afterPropertiesSet方法执行");
  }

  public void initMethod() {
    System.out.println("initMethod方法执行!");
  }
}

public class BeanInstantiationInitDemo {

  @Bean(value = "user", initMethod = "initMethod")
  public User user() {
    return new User();
  }

  public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    applicationContext.register(BeanInstantiationInitDemo.class);
    applicationContext.refresh();

    System.out.println("applicationContext.getBean(User.class) = " + applicationContext.getBean(User.class));
    applicationContext.close();
  }
}

执行结果:

@PostConstruct初始化执行
InitializingBean中的afterPropertiesSet方法执行
initMethod方法执行!
applicationContext.getBean(User.class) = User{name='null', sex=null}

接下来我们就进入源码来看一下这个执行顺序的原因:

@PostConstruct注解:

上面也说了,在Spring中存在一个后置处理器叫做InitDestroyAnnotationBeanPostProcessor,他专门处理通过注解实现的初始化方式,我们通过代码来看一下他的几个重要部分:

  1. 1. 筛选并记录被标记为初始化/销毁的方法
public class InitDestroyAnnotationBeanPostProcessor {

  // 标记初始化和销毁注解
  @Nullable
  private Class<? extends Annotation> initAnnotationType;
  @Nullable
  private Class<? extends Annotation> destroyAnnotationType;

  // 在执行Bean定义信息后置处理器时筛选出被指定注解标注的方法
  // 最后标记的初始化和销毁存储在LifecycleMetadata中
  @Override
  public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    LifecycleMetadata metadata = findLifecycleMetadata(beanType);
    metadata.checkConfigMembers(beanDefinition);
  }

  private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
    // 缓存中不存在就直接去构建
    if (this.lifecycleMetadataCache == null) {
      return buildLifecycleMetadata(clazz);
    }
    // 缓存中存在尝试从缓存中获取
    LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
    // ...
    return metadata;
  }

  private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
    // 先校验对象方法中是否包含对应注解标注的方法
    if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
      return this.emptyLifecycleMetadata;
    }

    // 下面就是将初始化和销毁方法封装为LifecycleElement,然后存储到LifecycleMetadata中
    List<LifecycleElement> initMethods = new ArrayList<>();
    List<LifecycleElement> destroyMethods = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
      final List<LifecycleElement> currInitMethods = new ArrayList<>();
      final List<LifecycleElement> currDestroyMethods = new ArrayList<>();

      ReflectionUtils.doWithLocalMethods(targetClass, method -> {
        if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
          LifecycleElement element = new LifecycleElement(method);
          currInitMethods.add(element);
        }
        if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
          currDestroyMethods.add(new LifecycleElement(method));
        }
      });

      initMethods.addAll(0, currInitMethods);
      destroyMethods.addAll(currDestroyMethods);
      targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);

    return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
            new LifecycleMetadata(clazz, initMethods, destroyMethods));
  }
}
  1. 1. 执行标记了初始化和销毁的方法
public class InitDestroyAnnotationBeanPostProcessor {

  // 在初始化前后置处理器中进行执行
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
    try {
      // 执行了LifecycleMetadata中的invokeInitMethods方法
      metadata.invokeInitMethods(bean, beanName);
    }
    catch (InvocationTargetException ex) {
      throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
    }
    catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
    }
    return bean;
  }
}

那我们看一下LifecycleMetadata#invokeInitMethods方法:

private class LifecycleMetadata {
  // 第一步中存储的初始化以及销毁方法,一个对象中可以有多个
  private final Collection<LifecycleElement> initMethods;
  private final Collection<LifecycleElement> destroyMethods;

  public void invokeInitMethods(Object target, String beanName) throws Throwable {
    Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
    Collection<LifecycleElement> initMethodsToIterate =
      (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
    if (!initMethodsToIterate.isEmpty()) {
      // 遍历执行所有的初始化方法
      for (LifecycleElement element : initMethodsToIterate) {
        // 内部就是执行 method.invoke(target, (Object[]) null)方法
        element.invoke(target);
      }
    }
  }
}

我们看到了使用注解去执行方法的实现,却没有看到@PostConstruct@PreDestroy这两个注解,其实是因为@PostConstruct@PreDestroy两个注解是在CommonAnnotationBeanPostProcessor中定义的,而CommonAnnotationBeanPostProcessor实现了InitDestroyAnnotationBeanPostProcessor,定义的详情我们可以在CommonAnnotationBeanPostProcessor构造器中看到。

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor{
  
  public CommonAnnotationBeanPostProcessor() {
    setOrder(Ordered.LOWEST_PRECEDENCE - 3);
    setInitAnnotationType(PostConstruct.class);
    setDestroyAnnotationType(PreDestroy.class);
  }
}

实现 InitializingBean 接口的 afterPropertiesSet() 方法:

这种实现比上面的就简单的很多很多,我们一看代码就知道了

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
  throws Throwable {
  // 看看对象是否继承InitializingBean接口
  boolean isInitializingBean = (bean instanceof InitializingBean);
  if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
    // 继承则强转并执行afterPropertiesSet方法
    ((InitializingBean) bean).afterPropertiesSet();
  }
  
  // 使用@Bean或者xml中initMethod定义的初始化方法
  invokeCustomInitMethod(beanName, bean, mbd);
}

使用@Bean或者xml中initMethod定义的初始化方法:

该方式实现也是比较简单的:

invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd):

protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd)
  throws Throwable {
    // 获得配置的初始化方法名称
  String initMethodName = mbd.getInitMethodName();

  // 通过名称获得Method对象
  Method initMethod = (mbd.isNonPublicAccessAllowed() ?
                       BeanUtils.findMethod(bean.getClass(), initMethodName) :
                       ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
  Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);

  // 反射执行
  ReflectionUtils.makeAccessible(methodToInvoke);
  methodToInvoke.invoke(bean);
}

本节一开头就讲了并且演示了三种初始化方法的执行顺序是@PostConstruct -> InitializingBean -> @Bean,从源码层面我们也看出来了,由于基于注解的初始化方法是在初始化前的后置处理器InitDestroyAnnotationBeanPostProcessor中执行的,所以注解方式最先执行,然后是校验了对象是否实现了InitializingBean接口,如果实现执行afterPropertiesSet方法,所以InitializingBean第二执行,最后才是在invokeCustomInitMethod方法中执行自定义的初始化方法。

执行初始化后的后置处理器

初始化后的后置处理器执行方式和初始化前的后置处理器差不多,代码超级简单,我们看一下就清楚了:

applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName):

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
  throws BeansException {

  Object result = existingBean;
  for (BeanPostProcessor processor : getBeanPostProcessors()) {
    Object current = processor.postProcessAfterInitialization(result, beanName);
    if (current == null) {
      return result;
    }
    result = current;
  }
  return result;
}

到这里结束,我们的一个对象的创建生命周期就算是结束了,这个对象就可以正常使用了。

Bean的销毁

Bean在上一步结束我们就拿到手使用了,但是至此Bean的生命周期并没有结束,一个单例Bean处理具有创建实例过程的生命周期(原型只有创建时的生命周期,没有销毁的生命周期),还具有销毁的生命周期,接下来我们就看一下一个Bean的销毁处理过程。

其实一个Bean的销毁过程经历和初始化这个过程时相似的,只不过前者是为了初始化,后者是为了销毁。

销毁也可以分为三个步骤:

  • • 执行销毁前的后置处理器 - @PreDestroy注解处理方式
  • • 执行DisposableBean对象的destroy()方法
  • • 执行自定义的destroyMethod

我们先来用一个案例来进行说明:

public class User implements InitializingBean, DisposableBean {

  private String name;

  private Integer sex;

  // .... get、set、toString方法

  @PreDestroy
  public void preDestroy() {
    System.out.println("@PreDestroy销毁执行");
  }

  @Override
  public void destroy() throws Exception {
    System.out.println("DisposableBean中的destroy方法执行");
  }

  public void destroyMethod (){
    System.out.println("destroyMethod方法执行!");
  }
}

public class BeanInstantiationDestroyDemo {

  @Bean(value = "user", initMethod = "destroyMethod")
  public User user() {
    return new User();
  }

  public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    applicationContext.register(BeanInstantiationDestroyDemo.class);
    applicationContext.refresh();

    System.out.println("applicationContext.getBean(User.class) = " + applicationContext.getBean(User.class));
    applicationContext.close();
  }
}

执行结果:

applicationContext.getBean(User.class) = User{name='null', sex=null}
@PreDestroy销毁执行
DisposableBean中的destroy方法执行
destroyMethod方法执行!

我们可以看到,销毁的过程其实可初始化的过程也是一样的:@PreDestroy->DisposableBean->destroyMethod

由于处理出过程比较简单,我们就整合在一起看了,下面我们通过源码来看一下:

销毁过程主要是在DisposableBeanAdapter对象中:

class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
  @Override
  public void destroy() {

    // 1、执行销毁前后置处理器。@PreDestroy处理便是在这步进行,具体处理过程参考执行初始化方法中的过程
    if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
      for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
        processor.postProcessBeforeDestruction(this.bean, this.beanName);
      }
    }

    // 2、执行DisposableBean对象的destroy()方法
    if (this.invokeDisposableBean) {
      ((DisposableBean) this.bean).destroy();
    }

    // 3、执行自定义的`destroyMethod`
    invokeCustomDestroyMethod(this.destroyMethod);
  }

  private void invokeCustomDestroyMethod(final Method destroyMethod) {
    int paramCount = destroyMethod.getParameterCount();
    final Object[] args = new Object[paramCount];
    if (paramCount == 1) {
      args[0] = Boolean.TRUE;
    }

    // 通过反射执行自定义销毁方法
    ReflectionUtils.makeAccessible(destroyMethod);
    destroyMethod.invoke(this.bean, args);
  }
}

Bean的销毁过程和执行初始化方法的过程是相同的,这个执行过程相对比较简单,我们只需要记住三种销毁方式的执行顺序是@PreDestroy->DisposableBean->destroyMethod就行

总结

整体来看Bean创建到销毁的整个生命周期还是比较复杂的,下面我们梳理一下Bean创建到销毁执行的相关方法顺序:

BeanDefinition处理:

  • • AbstractBeanFactory#getMergedLocalBeanDefinition 合并Bean定义
  • • AbstractBeanFactory#resolveBeanClass 获得Class对象

实例化阶段:

  • • InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 实例化前后置处理
  • • 实例化
  • • MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition BeanDefinition处理器
  • • InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation 实例化前后置处理
  • • InstantiationAwareBeanPostProcessor#postProcessProperties PropertyValues处理器

初始化阶段:

  • • Aware 接口回调
  • • BeanPostProcessor#postProcessBeforeInitialization 初始化前置处理
  • • InitializingBean#afterPropertiesSet
  • • 自定义initMethod方法
  • • BeanPostProcessor#postProcessAfterInitialization 初始化后置处理

销毁阶段:

  • • DestructionAwareBeanPostProcessor#postProcessBeforeDestruction 销毁前后置处理
  • • DisposableBean#destroy
  • • 自定义destroyMethod方法

注意:多例会有实例化及其实例化之前的所有操作,但是不会有销毁阶段的操作,因为我们不知道多例什么时候会被销毁。

扩展

我们知道,一个Bean在没有被声明成懒加载的形式的话,那么在项目启动的时候就会去加载然后创建好缓存所有的Bean,那么这个过程在那里实现呢?

答案是在DefaultListableBeanFactory中的preInstantiateSingletons方法会在项目启动的时候实例化所有(非惰性init)singleton bean。

我们来简单的看一下这个方法:

preInstantiateSingletons():

@Override
public void preInstantiateSingletons() throws BeansException {
  // 获得所有的beanDefinition名称
  List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

  // 遍历所有Bean定义信息然后对非懒惰单例bean进行初始化
  for (String beanName : beanNames) {
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    // 不是抽象的、单例的、不是懒加载的
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        getBean(beanName); 
    }
  }
}

Spring Bean作用域_xml_05

单例与原型

单例是Spring中默认的Bean实现方式,在Spring中校验一个Bean是单例还是原型是通过BeanDefinition来进行确认的,在我们使用BeanFactory#getBean的时候,我们可以看到里面的实现就是通过判断isSingletonisPrototype判断出创建的对象应该是单例还是原型。

下面是getBean创建对象实例时最终会执行的部分代码(其中的mbd就是BeanDefinition):

但是有一点需要我们去注意,单例由于在整个IOC容器中唯一,所以,Spring是会管理他完整的生命周期的,但是原型创建出对象后Spring就不知道改什么时候会被销毁,所以无法执行销毁方法回调。

其他作用域

除了单例与原型的作用域是通过BeanDefinition校验之外,其他的作用域都是通过实现Scope接口的方式来进行实现的。

request、session和application的作用域实现类分别是RequestScopeSessionScopeServletContextScopeRequestScope是基于一次请求,所以他Bean是存储与ThreadLocal中,SessionScope是基于会话,所以通过session-id查找对应的Bean信息,而ServletContextScope是直接将Bean存储在ServletContext中,而他们注册是在WebApplicationContextUtils进行的,对于三个作用域的实现逻辑也比较简单,感兴趣的可以自己下去看看。

WebApplicationContextUtils#registerWebApplicationScopes()

Spring Bean作用域_生命周期_06

自定义作用域

实现一个作用域,基于线程内Bean是单例的。

自定义作用域:

public class ThreadScope implements Scope {

  public static final String NAME = "threadScope";

  // 存放于ThreadLocal中
  private ThreadLocal<Map<String, Object>> tl = ThreadLocal.withInitial(() -> new HashMap<>());

  @Override
  public Object get(String name, ObjectFactory<?> objectFactory) {
    // 基于线程id取,如果取不到则创建
    Map<String, Object> map = tl.get();
    Object o = map.get(getThreadId());
    if (Objects.isNull(o)) {
      o = objectFactory.getObject();
      map.put(getThreadId(), o);
    }
    return o;
  }

  @Override
  public Object remove(String name) {
    return tl.get().remove(getThreadId());
  }

  @Override
  public void registerDestructionCallback(String name, Runnable callback) {

  }

  @Override
  public Object resolveContextualObject(String key) {
    return null;
  }

  @Override
  public String getConversationId() {
    // 基于线程id
    return getThreadId();
  }

  private String getThreadId() {
    return Thread.currentThread().getId() + "";
  }
}

测试:

public class CustomBeanScopeDemo {

  @Bean
  @Scope(ThreadScope.NAME)
  public ScopeEntity scopeEntity() {
    return new ScopeEntity(System.currentTimeMillis(), "自定义作用域");
  }

  public static void main(String[] args) throws InterruptedException {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
    annotationConfigApplicationContext.register(CustomBeanScopeDemo.class);
    // 注册作用域
    annotationConfigApplicationContext.addBeanFactoryPostProcessor(beanFactory -> beanFactory.registerScope(ThreadScope.NAME, new ThreadScope()));
    annotationConfigApplicationContext.refresh();

    // 创建三个线程,校验是否每个线程中的对象都相等
    for (int i = 0; i < 3; i++) {
      Thread thread = new Thread(() -> {
        ScopeEntity bean1 = annotationConfigApplicationContext.getBean(ScopeEntity.class);
        ScopeEntity bean2 = annotationConfigApplicationContext.getBean(ScopeEntity.class);
        ScopeEntity bean3 = annotationConfigApplicationContext.getBean(ScopeEntity.class);

        System.out.println(Thread.currentThread().getName() + "线程中bean1的值为:" + bean1);
        System.out.println(Thread.currentThread().getName() + "线程中bean2的值为:" + bean2);
        System.out.println(Thread.currentThread().getName() + "线程中bean3的值为:" + bean3);
      }, "thread-" + i);
      thread.start();
      thread.join();
    }

    annotationConfigApplicationContext.close();
  }
}