Spring Bean是如何创建的——Spring IOC系列(一)

421 阅读7分钟

一、概述

本文分析下Spring的Bean是如何创建的,核心关注Bean的“创建”流程。假设我们已经有了一个Bean的定义,而不去纠结Bean的定义(BeanDefinition)是怎么来的,基于此,梳理它的创建过程。本文会结合一些源码讲解,但不会特别详细,只是帮你梳理一个大纲,有兴趣可以结合本文,对spring的源码进行深入分析。

🤔Bean创建的主要步骤

Spring Bean的创建的源码,在AbstractAutowireCapableBeanFactory#doCreateBean方法中实现,主要的几个步骤:

  1. 实例化(createBeanInstance):通过反射或者工厂方法创建bean的实例。
  2. 依赖注入(populateBean): 对@Vaue/@Autowired/@Resource等依赖的注入。
  3. 初始化(initializeBean): 执行bean定义的初始化方法
  4. 注册销毁方法(registerDisposableBeanIfNecessary),如果bean指定了销毁方法,需要注册销毁方法,以在Spring容器关闭时,执行对应的方法。

二、解析

2.1 实例化(createBeanInstance)

创建bean,spring首先需要实例化这个bean,也就是通过反射或者工厂方法创建bean的实例。核心就是这个createBeanInstance:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // ...忽略一些检查代码...

    // 。BeanDefinition定义了supplier属性,使用supplier方法创建
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }

    // 。BeanDefinition定义了工厂方法,使用工厂方法创建
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // 。之前已经解析过使用哪个构造方法,直接使用
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            return instantiateBean(beanName, mbd);
        }
    }

    // 。调用SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors扩展方法,
    //   获取候选构造器,如果返回不为null,则使用选定的构造器
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    // 。候选构造器不为空 || mode = AUTOWIRE_CONSTRUCTOR || 有参数,使用构造器构造
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // BeanDefinition子类可以实现getPreferredConstructors方法,选择更候选构造方法,默认返回null
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        return autowireConstructor(beanName, mbd, ctors, null);
    }

    // 默认使用无参构造器
    return instantiateBean(beanName, mbd);
}

大致流程:

  1. 通过BeanDefinition定义的Supplier或者工厂创建对象。
  2. 之前已经解析过使用哪个构造方法,直接使用,否则需要解析使用哪个构造方法。
  3. 调用SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors扩展方法,获取候选构造器,如果返回不为null,则使用选定的构造器。
  4. 上一步返回的构造器不为null || 构造模式为构造器构造 || 存在参数,则使用构造器构造。
  5. 如果BeanDefinition子类重写了getPreferredConstructors方法,返回了不为null的候选构造器,使用候选构造器构造。
  6. 默认使用无参构造器。

PS:

  • @Bean注解定义的bean的BeanDefinition,@Bean方法会被转换为一个工厂方法,用于实例化。
  • AutowiredAnnotationBeanPostProcessor实现了determineCandidateConstructors方法,用于选定构造函数。
    1. 存在@Autowired标识的构造器
      • required属性为true(默认为true),则使用该构造器,如果有多个为true,报错。
      • required属性为false,则作为候选构造器,与默认无参构造器(如果存在)一起返回。
    2. 无@Autowired标识构造器,但仅有一个构造方法,且参数不为空,返回该构造器。
    3. 其他返回null。

autowireConstructor比较复杂,没有深入研究。

2.2 依赖注入(populateBean)

实例化完成后,Spring执行了一个扩展方法,MergedBeanDefinitionPostProcessor接口的postProcessMergedBeanDefinition方法。

// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
    //每个bean仅处理一次
	if (!mbd.postProcessed) {
		try {
			applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Post-processing of merged bean definition failed", ex);
		}
		mbd.postProcessed = true;
	}
}

注意:这里是加锁了,并且通过BeanDefinition#postProcessed属性,判断是否处理过,也就是说,这个applyMergedBeanDefinitionPostProcessors方法,只会执行一次。

因此,这里适合对BeanDefinition的一些元数据信息进行解析,并缓存(只执行一次)。AutowiredAnnotationBeanPostProcessor(Autowired的注解实现类),就是通过该扩展方法,解析并缓存BeanDefinition的@Autowired、@Value等注解信息。

该扩展方法完成后,包装Bean形成了一个工厂方法,放入了缓存中,用来解决循环依赖问题,不是本文的重点,不纠结。之后就到了重点populateBean方法,用来依赖注入,可以使用xml或者@Autowired/@Resource/@Value等注解,定义依赖的属性。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {

    // ...省略一些检查代码...
    // 。执行实例化后的扩展方法
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                return;
            }
        }
    }

    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    // 。根据类型或者名字获取需要自动注入的属性,一般这段代码不会走,因为默认的是AUTOWIRE_NO
    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // Add property values based on autowire by name if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // Add property values based on autowire by type if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }

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

    // 。执行InstantiationAwareBeanPostProcessor的postProcessProperties和postProcessPropertyValues方法。
    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                if (filteredPds == null) {
                    filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                }
                pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                    return;
                }
            }
            pvs = pvsToUse;
        }
    }
    if (needsDepCheck) {
        if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        }
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }
    // 。执行配置的依赖注入
    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

大致流程

  1. 执行实例化后扩展方法,也就是InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
  2. 根据策略查找依赖的属性,一般不会执行,因为默认的注入策略为AUTOWIRE_NO,也就是只会注入xml配置的或者注解修饰的属性。
  3. 执行InstantiationAwareBeanPostProcessor的postProcessProperties和postProcessPropertyValues方法。
    • postProcessProperties,在属性注入前执行,可以修改或者校验属性。PS:AutowiredAnnotationBeanPostProcessor,在这里对Autowired的属性进行注入。
    • postProcessPropertyValues,已经被标记废弃,建议使用postProcessProperties替代。
  4. 对BeanDefinition中配置的属性进行注入。

到这里,我们大概知道了@Autowired是如何实现的了。实现类为AutowiredAnnotationBeanPostProcessor,它实现了

  • SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors,用于实现优先使用@Autowired修饰的构造方法。
  • MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition,在实例化后,解析Bean有哪些属性/方法,被Autowired注解修改,并缓存起来。
  • InstantiationAwareBeanPostProcessor#postProcessProperties,在populateBean方法中,获取在postProcessMergedBeanDefinition时已经解析的元数据信息,进行依赖注入。

2.3 初始化(initializeBean)

依赖注入之后,Bean就可以执行定义的初始化操作了,那么

🤔Bean如何定义初始化方法

  1. 在xml或者@Bean注解中使用的init-method属性,指定初始化方法。
  2. 实现InitializingBean接口的afterPropertiesSet方法。
  3. 使用@PostConstruct注解指定初始化方法。

初始化方法的入口为AbstractAutowireCapableBeanFactory#initializeBean,源码:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    //。如果Bean实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware等接口,注入相关的属性
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    //。执行BeanPostProcessor初始化前置扩展方法,即postProcessBeforeInitialization
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        //。执行初始化方法
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        //。执行BeanPostProcessor初始化后置方法,即PostProcessorsAfterInitialization
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

流程非常清晰

  1. 为实现BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口的Bean,注入BeanName/ClassLoader/BeanFactory等属性。注意:
    • 此处为invokeAwareMethods硬编码实现,仅支持以上三个Aware接口。诸如ApplicationContextAware等Aware接口,是ApplicationContextAwareProcessor这个BeanPostProcessor通过postProcessBeforeInitialization(也就是下个步骤)实现的。
  2. 执行BeanPostProcessor初始化前置扩展方法,即postProcessBeforeInitialization。举栗子:
    • ApplicationContextAware通过该方法,实现了ApplicationContextAwareResourceLoaderAware等Aware接口注入;
    • InitDestroyAnnotationBeanPostProcessor通过该方法,实现了@PostConstruct注解。
  3. 执行初始化方法。注意这里的初始化方法不包括@PostConstruct,该注解是在上一步实现的。
  4. 执行BeanPostProcessor初始化后置方法,即PostProcessorsAfterInitialization。举栗子:
    • AbstractAutoProxyCreator通过该方法,对Bean进行了动态代理。

🤔面试题:@PostConstruct和InitializingBean接口的afterPropertiesSet哪个先执行?

答:@PostConstruct先执行,该注解是InitDestroyAnnotationBeanPostProcessor通过postProcessBeforeInitialization方法在初始化方法之前执行的,自然在初始化方法之前执行。

2.4 注册销毁方法(registerDisposableBeanIfNecessary)

如果bean指定了销毁方法,需要注册销毁方法,以在Spring容器关闭时,执行对应的方法。

🤔Bean如何定义销毁方法

与初始化方法类似

  1. 在xml或者@Bean注解中使用的destroy-method属性,指定初始化方法。
  2. 实现DisposableBean接口的afterPropertiesSet()方法。
  3. 使用@PreDestroy注解指定销毁方法。

registerDisposableBeanIfNecessary方法比较简单,就是判断是否有以上定义的销毁方法,存在,则注册一下(也就是放到map中),用于容器关闭时执行相关方法。

三、小结

到此为止,Spring Bean的创建就分析完成了,可以看到,实例化 -> 依赖注入 -> 初始化这个过程中,Spring提供了大量的BeanPostProcessor扩展方法。那么我们下期,就来分析下,BeanPostProcessor。

参考: