手撕源码之Spring中Bean的创建

170 阅读6分钟

在《Spring创建BeanDefinition之路径扫描》《Spring中@Component和@Bean的底层逻辑》中,我们已了解了如何创建BeanDefinition。现在,我们一起来看看Bean的创建过程。

本文中源码来自Spring 5.3.x分支,github源码地址:github.com/spring-proj…

当我们创建了ApplicationContext对象后,就可以从中获取指定的Bean对象了。来看一个示例:

package com.xiakexing.service;

import org.springframework.stereotype.Component;

@Component
public class UserService {

    public void test() {
        System.out.println("hello spring");
    }
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean("userService", UserService.class);
userService.test();

在执行context.getBean("userService", UserService.class)前,容器中已经存在userService对象了。该对象是什么时候创建的呢?

一 引入

在创建AnnotationConfigApplicationContext对象时,会调用refresh(),其中会实例化所有非懒加载单例Bean。 最终会调用DefaultListableBeanFactory#preInstantiateSingletons:

  1. 首先遍历所有的BeanDefinition对象,根据它来创建Bean对象;
  2. 当所有单例Bean都被创建后,执行SmartInitializingSingleton回调。
@Override
public void preInstantiateSingletons() throws BeansException {
	if (logger.isTraceEnabled()) {
		logger.trace("Pre-instantiating singletons in " + this);
	}

	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	for (String beanName : beanNames) {
		// merge 父子BeanDefinition,属性复写
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// BeanDefinition可以是抽象的
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			// 创建工厂bean
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					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());
					}
					// 立即创建FactoryBean管理的bean
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			}
			else {
				// 创建普通Bean
				getBean(beanName);
			}
		}
	}

	// 执行SmartInitializingSingleton回调
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
			.tag("beanName", beanName);
			SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			} else {
				smartSingleton.afterSingletonsInstantiated();
			}
			smartInitialize.end();
		}
	}
}

二 准备实例化

2.1 合并BeanDefinition

Spring中支持父子BeanDefinition,和Java父子类相似。子BeanDefinition可以继承父BeanDefinition的属性值,也可以进行复写

比如,child的scope默认是singleton,因此是单例Bean。

<bean id="father" class="com.zhouyu.service.Father" scope="prototype"/> 
<bean id="child" class="com.zhouyu.service.Child"/> 

当指定child的parent属性时,child就和father一样,变成原型Bean了,它从父BeanDefinition中继承了自己未定义的scope属性指。

<bean id="father" class="com.zhouyu.service.Father" scope="prototype"/> 
<bean id="child" class="com.zhouyu.service.Child" parent="father"/> 

因此,Spring在创建Bean对象之前,需要进行父子BeanDefinition合并,保证属性完整。

合并后的BeanDefinition会保存到AbstractBeanFactory#mergedBeanDefinitions中(Map结构):

其实,父子BeanDefinition实际应用的很少。

当合并后的BeanDefinition,不是Abstract的、单例的且非懒加载的,才会进行Bean实例化。

2.2 区分工厂Bean和普通Bean

对于普通Bean,调用构造器创建即可。但是,对于FactoryBean接口实现,除了创建工厂Bean对象外,还要创建它所管理的Bean。

  1. 首先判断当前BeanDefinition是不是FactoryBean的。此时会加载Class文件到JVM中,根据class对象来判断。

注意,起初在BeanDefinition对象中,BeanDefinition的beanClass属性存储的是当前类的全类名,而不是class对象

  1. 如果当前BeanDefinition是FactoryBean接口的实现,给beanName加前缀&,尝试从单例池中获取工厂bean对象,没有则创建;
  2. 如果工厂Bean是SmartFactoryBean接口的实现,且isEagerInit()返回true,则表示要立即创建FactoryBean管理的bean,则会调用getBean(beanName),将结果缓存到factoryBeanObjectCache中(Map结构)。

2.3 处理@dependsOn

创建Bean的逻辑在AbstractBeanFactory#doGetBean中。

  1. 先将入参name转为标准的beanName,主要是将别名转为真正的beanName;
  2. 尝试从当前容器中获取Bean对象,如果没有,则尝试从父容器中获取;如果都没有,进入创建环节;
  3. 根据合并后的BeanDefinition,判断@dependsOn是否会引起循环依赖,存在循环依赖则报错。
  4. 如果没有循环依赖,则注册Bean的依赖关系到Map中;
  5. 先创建所依赖的所有Bean对象;最后再创建当前Bean。

三 创建Bean对象

已创建的单例Bean,会被缓存到单例池singletonObjects(Map结构)中。

在DefaultSingletonBeanRegistry#getSingleton()方法中,当用beanName从单例池中获取不到Bean时,就使用入参ObjectFactory创建Bean,并在添加到单例池中。

3.1 实例化前

首先,加载BeanDefinition对应的Class,创建class对象,并赋值给BeanDefinition.beanClass属性。

Spring提供了一个扩展点,在实例化对象之前,允许执行用户的自定义动作:InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()。

当postProcessBeforeInstantiation()有返回值时,表示我们自行完成了实例化,不需要Spring介入;那么依赖注入、初始化前、初始化都不会执行,直接到初始化后阶段。

3.2 实例化

在AbstractAutowireCapableBeanFactory#createBeanInstance中,

  1. 如果BeanDefinition.instanceSupplier有值, 则调用Supplier.get()创建对象;

  2. 如果BeanDefinition.factoryMethodName有值,说明是用@Bean定义的,调用method.invoke();

    1. factoryBeanName有值,说明是工厂方法;
    2. factoryBeanName无值,说明是静态工厂方法;
  3. 否则,对于@Component等定义的Bean,推断出合适的构造方法(当类中有多个构造器时),反射创建Bean。

3.3 实例化后

Bean对象实例化后、属性赋值之前,spring又提供了一个扩展点: MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(),用于修改合并后BeanDefinition。 它有个默认实现AutowiredAnnotationBeanPostProcessor,用于寻找@Autowired注解的注入点,并缓存在AutowiredAnnotationBeanPostProcessor.injectionMetadataCache(Map结构)中。

还会执行InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(),用于在设置属性之前修改bean的状态(即属性)。

3.4 自动注入

执行InstantiationAwareBeanPostProcessor.postProcessProperties(),处理@Autowired、@Resource、@Value等注解,实现依赖自动注入。(我们之后在细看)

3.5 执行Aware回调

完成属性赋值后,在AbstractAutowireCapableBeanFactory#invokeAwareMethodsSpring中,Spring会执行一些回调,包括:

  • BeanNameAware:回传beanName给bean对象。
  • BeanClassLoaderAware:回传classLoader给bean对象。
  • BeanFactoryAware:回传beanFactory给对象。

3.6 初始化前

即遍历所有BeanPostProcessor实现,执行postProcessBeforeInitialization方法。

源码中有两个实现:

  1. ApplicationContextAwareProcessor:进行其他Aware回调,包括

    1. EnvironmentAware:回传环境变量
    2. EmbeddedValueResolverAware:回传占位符解析器
    3. ResourceLoaderAware:回传资源加载器
    4. ApplicationEventPublisherAware:回传事件发布器
    5. MessageSourceAware:回传国际化资源
    6. ApplicationStartupAware:回传应用监听对象,可忽略
    7. ApplicationContextAware:回传Spring容器ApplicationContext
  2. InitDestroyAnnotationBeanPostProcessor,执行@PostConstruct标注的方法。

3.7 初始化

执行AbstractAutowireCapableBeanFactory#invokeInitMethods,包括两步:

  1. 查看当前Bean对象是否实现了InitializingBean接口,如果是就调用afterPropertiesSet();
  2. 执行@Bean指定的init-mothed。

3.8 初始化后

创建Bean的最后一个步骤,Spring提供了一个扩展点:BeanPostProcessor.postProcessAfterInitialization()。

Spring AOP就是在此处实现的,初始化后返回的对象(可能是代理对象)才是最终的Bean。

四 流程图

image.png

五 总结

我们手动创建一个Bean时,感觉很简单。而Spring容器创建Bean时,由于提供了多种方式,提供了很多扩展点,需要解决循环依赖,实现自动注入和aop代理,因此过程变得很复杂。

了解源码后,有以下几点需注意:

  • 由@dependsOn造成的循环依赖,Spring无法解决,只会报错。
  • 由FactoryBean创建的Bean,只会经历初始化后阶段,没有其他阶段,因为Bean的实例化、初始化完全由程序员自行定义了;
  • 单例池中会保存FactoryBean对象,而FactoryBean所管理的单例Bean,保存在FactoryBeanRegistrySupport.factoryBeanObjectCache缓存中;
  • 自定义Bean实现Aware接口时,复写setXXX方法,在源码中由Spring完成回调;
  • 在执行顺序上,@PostConstruct > InitializingBean.afterPropertiesSet > init-mothed;
  • Spring AOP在最后阶段——初始化后被实现,一个类被代理后,单例池中只会保存代理类对象。