【Spring源码核心篇-01】精通Spring的bean的生命周期

Spring源码核心篇整体栏目


内容链接地址
【一】Spring的bean的生命周期https://zhenghuisheng.blog.csdn.net/article/details/143441012
【二】深入理解spring的依赖注入和属性填充https://zhenghuisheng.blog.csdn.net/article/details/143854482

如需转载,请附上链接:https://blog.csdn.net/zhenghuishengq/article/details/143441012

一,spring中bean的生命周期

在本人前面的文章中,也写过一些关于spring源码的一些核心方法,主要是对spring中refresh中的九个方法进行的一些源码剖析,接下来的spring系列主要为核心篇,就是疏通spring的主干和脉络,通过spring的主干来了解spring的IOC和aop。源码依旧可以选择5.2的版本: https://github.com/spring-projects/spring-framework/tree/5.2.x

本文主要的内容就是了解spring的IOC中,bean的什么周期以及流程是怎么样的,结合bean的生命周期,了解一些spring中的一些扩展点机制,如bean的前置处理器,后置处理器,bean实例化前能做的事情,bean实例化后做的事情,bean初始化前做的事情,bean初始化后做的事情等

本人通过读取一下源码锁总结的流程图如下:

在这里插入图片描述

1,生成BeanDefinition

首先第一步是生成一个Bean定义,如何理解这个Bean定义,就是类似于我要做一个家具,在做之前需要找一个加工厂帮忙做好,但是加工厂并不知道要做成什么样子,因此就需要我们定义好一份图纸交给工厂,那么这个图纸就是所谓的BeanDefinition,然后这个工厂就是对应的spring容器

1.1,初始化context和BeanFactory

在spring中,主要有注解的方式和xml启动上下文,这里直接选用注解的方式启动上下文

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();

这个对象的继承关系如下,继承了 GenericApplicationContext 类,实现了 AnnotationConfigRegistry 接口

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {}

在初始化这个 AnnotationConfigApplicationContext 对象之后,可以发现这个对象是 BeanFactory 的一个实现类,也就是说在初始化这个context上下文之前,还会先初始化一个 BeanFactory 的工厂,并且BeanFactory工厂有的功能context上下文都有,context就是一个BeanFactory的一个具体实现

在这里插入图片描述

接下来以下面这个包路径的源码进行分析,如分析一段service包下面的所有注解是如何注册到spring中生产bean对象,AnnotationConfigApplicationContext 其他的几个构造方法可以先不看

public AnnotationConfigApplicationContext(String... basePackages) {
	this();		//注册一个读取器和扫描器,也可以先不看
	scan(basePackages);	//扫描包路径
	refresh();			//spring中最核心的方法,refresh方法
}

1.2,核心doScan方法

然后直接分析这个scan方法,一直往下点,可以看到一个 doScan 方法,就是扫描的核心方法,然后会循环的寻找包路径集合,最后回去找每一个路径下面的有 @Component 注解的bean,然后将bean生成一个 BeanDefinition

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	//创建bean定义的holder对象用于保存扫描后生成的bean定义对象
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
	//循环我们的包路径集合
	for (String basePackage : basePackages) {
		//找到候选的Components
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		for (BeanDefinition candidate : candidates) {
			//拿到元数据解析器,可以获取类中所有信息
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			candidate.setScope(scopeMetadata.getScopeName());
			//设置我们的beanName
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			//这是默认配置 autowire-candidate
			if (candidate instanceof AbstractBeanDefinition) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			//获取@Lazy @DependsOn等注解的数据设置到BeanDefinition中
			if (candidate instanceof AnnotatedBeanDefinition) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			//把我们解析出来的组件bean定义注册到我们的IOC容器中(容器中没有才注册)
			if (checkCandidate(beanName, candidate)) {
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				definitionHolder =
						AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}

1.3,获取BeanDefinition

可以直接查看这个 findCandidateComponents 方法时如何获取到Bean定义的,内部主要会通过一个 scanCandidateComponents 方法来具体的扫描这些带有@Component注解的主键,如下图所示

如一个com.zhs.service的包下面有一个OrderService的类:

  • 这个方法首先会获取到这个包路径为 com.zhs.service
  • 然后获取到该包下面的全部带有 .class 类文件,将这个OrderService类封装成一个Resource资源
  • 遍历每个资源,判断是否在includeFilters中或者excludeFilters中,Component在容器启动已经加入到includeFilters中,所以有这个注解的会生成一个BeanDefinition被选中加入到集合中

在这里插入图片描述

这里还有一个细节,就是在下面这行代码中,设置到这个Bean的ClassName还是这个类的名字,而不是一个对象,在后面实例化之后那么设置的就是一个Object的对象了,并且这个 beanClass 原本就是一个Object的对象,因为此时在容器启动时,目前还没有真正的bean对象被实例化

@Nullable
private volatile Object beanClass;	//原因是目前只扫描到了,但是并没有加载

ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);

public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
	this.metadata = metadataReader.getAnnotationMetadata();
	setBeanClassName(this.metadata.getClassName());
}

1.4,BeanDefinition属性赋值

在上面虽然获取到了BeanDefinition,但是这个bean定义里面只有名字,还需要给BeanDefinition设置一些基础属性,如是否懒加载,是否单例bean

在拿到 BeanDefinition 的set集合之后,会遍历这个set集合,为里面每一个bean定义进行属性赋值,首先是获取到每个bean定义的元数据解析器,可以获取到每个bean定义的所有属性,然后设置bean定义作用域

ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());

然后就是判断类是否懒加载,是否加了 @Dependson注解等,Dependson注解主要用于依赖关系,比如A上面加了一个依赖B的注解,那么在加载A实例前需要先加载B实例,这种方式造成的循环依赖解决不了,只能手动的避免

if (candidate instanceof AnnotatedBeanDefinition) {					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}

在这里插入图片描述

1.5,Bedefinition存入BeanDefinitionMap

最后会先判断当前bean定义是否已经存在于容器中,如果不存在的话,把我们解析出来的组件bean定义注册到spring的IOC容器中

if (checkCandidate(beanName, candidate)) {
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
	definitionHolder =
			AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	beanDefinitions.add(definitionHolder);
	registerBeanDefinition(definitionHolder, this.registry);
}

最后直接进入到这个 registerBeanDefinition 方法中,可以发现是直接通过一个工具类进行了注册

BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);

最后将这个BeanDefinition注册到BeanDefinitionMap

在这里插入图片描述

2,Bean工厂加载bean

上面说了beanDefinition是一张图纸,spring是一个加工厂,那么接下来就需要通过工厂将图纸生成对应的家具,就是需要通过spring将beanDefinitionMap中的全部beanDefinition生成对应的bean

2.1,实例化全部的单例bean

在通过scan扫描方法将全部的beanDefinition拿到之后,接下来的事情就是遍历全部的BeanDefinition,然后将BeanDefinition交给spring的bean工厂,直接来直接分析 refresh 中的初始化单例bean的方法

finishBeanFactoryInitialization(beanFactory);

在这个方法中,会有一个专门实例化单例bean的方法 preInstantiateSingletons

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    //实例化剩余的单实例bean
	beanFactory.preInstantiateSingletons();
}

在这个实例化单例bean的方法中,会遍历全部扫描拿到的单例beanDefinition,做以下流程:

  • 先判断这个beanDefinition是否为抽象的、单例的或者是否为懒加载的
  • 再次判断这个beanDefinition是否为工厂bean,是的话则需要特殊处理转化成对应的bean
  • 最后调用这个getBean方法去创建对应的实例,有这个实例则直接获取,无则创建

在这里插入图片描述

2.2,doGetBean

接下来就是进入bean工厂创建bean的方法,在进入上面的getBean方法之后,里面可以看到这个真正去创建bean的方法 doGetBean 方法

@Override
public Object getBean(String name) throws BeansException {
	//真正的获取bean的逻辑
	return doGetBean(name, null, null, false);
}

如下图所示,其部分流程如下:

  • 首先第一步就是获取到这个bean的别名,如果有别名则获取到别名,没有则用当前bean的名字
  • 随后去单例池的缓存中获取对象,默认绝大多数的对象都是单例对象

在这里插入图片描述

首先刚进来这个单例池里面肯定是没有对象的,因为还未初始化放到单例池里面,因此看后面的else逻辑。下面这段代码的逻辑也比较简单,就是判断这个BeanDefinition是否存在于单前的BeanFactory中,如果不存在,那么就去父工厂的BeanFactory中去获取

BeanFactory parentBeanFactory = getParentBeanFactory();
//若存在父工厂,切当前的bean工厂不存在当前的bean定义,那么bean定义是存在于父beanFacotry中
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
	//获取bean的原始名称
	String nameToLookup = originalBeanName(name);
	//若为 AbstractBeanFactory 类型,委托父类处理
	if (parentBeanFactory instanceof AbstractBeanFactory) {
		return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
				nameToLookup, requiredType, args, typeCheckOnly);
	}
	else if (args != null) {
		//  委托给构造函数 getBean() 处理
		return (T) parentBeanFactory.getBean(nameToLookup, args);
	}
	else {
		// 没有 args,委托给标准的 getBean() 处理
		return parentBeanFactory.getBean(nameToLookup, requiredType);
	}
}

如果没有父BeanFactory的话,那么就会继续往下走,其流程如下

  • 首先会拿到合并的RootBeanDefinition,这个才是最终交给bean工厂加载的BeanDefinition
  • 随后就是会对这个合并的RootBeanDefinition进行检查,判断是否抽象的等
  • 随后会校验这个 dependsOn 注解,就是前面所讲到的依赖于谁的注解,如A依赖于B,那么在创建A之前则需要将B先创建出来,这个注解方式避免不了循环依赖,只能手动解决
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查当前创建的bean定义是不是抽象的bean定义
checkMergedBeanDefinition(mbd, beanName, args);
//依赖bean的名称
String[] dependsOn = mbd.getDependsOn();
	if (dependsOn != null) {
	// <1> 若给定的依赖 bean 已经注册为依赖给定的 bean
	// 即循环依赖的情况,抛出 BeanCreationException 异常
	for (String dep : dependsOn) {
		//beanName是当前正在创建的bean,dep是正在创建的bean的依赖的bean的名称
		if (isDependent(beanName, dep)) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
		}
		//保存的是依赖 beanName 之间的映射关系:依赖 beanName - > beanName 的集合
		registerDependentBean(dep, beanName);
		try {
			//获取depentceOn的bean
			getBean(dep);
		}
		catch (NoSuchBeanDefinitionException ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
		}
	}
}

2.3,createBean

在对上面的那些东西进行校验完成之后,接下来就是真正的进入创建单例bean的方法,在单例方法中,首先会判断是否为单例bean,然后最终调用这个 createBean 方法进行bean的创建

//创建单例bean
if (mbd.isSingleton()) {
	//把beanName 和一个singletonFactory 并且传入一个回调对象用于回调
	sharedInstance = getSingleton(beanName, () -> {
		try {
			//进入创建bean的逻辑
			return createBean(beanName, mbd, args);
		}
		catch (BeansException ex) {
			//创建bean的过程中发生异常,需要销毁关于当前bean的所有信息
			destroySingleton(beanName);
			throw ex;
		}
	});
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
2.3.1,bean的前置处理器(实例化前)

接下来直接进入这个创建bean的主角 createBean 方法,也就是bean生命周期最重要的一部分,就是在这个方法里面,在这个方法里面,首先会在真正的doCreateBean创建bean之前,创建一个bean的前置处理器,aop的实现就是在这里去进行扫描所有的@AespectJ注解,然后扫描类内部的@Before,@after等注解,最后进行一个动态代理,这一步就是实例化前的操作

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
	throws BeanCreationException {
     try {
         //bean定义的前置处理器
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}   
}

在这个 resolveBeforeInstantiation中,可以在里面看到一下这段代码,将这个对应的切面解析并保存到缓存中

//bean的前置处理器
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
//bean的后置处理器
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);

在这里插入图片描述

2.3.2,实例化bean

在上面的getBean方法中继续往下走,可以发现一个真正的去创建实例bean的doCreateBean方法

try {
	/**
	 * 该步骤是我们真正的创建我们的bean的实例对象的过程
	 */
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}

方法如下图,首先会将这个Bean进行一个 BeanWrapper的包装,然后调用 createBeanInstance 进行bean的实例化,在进行实例化时,会对实例化的方式进行推断,如是否用构造方法、工厂方法等

instanceWrapper = createBeanInstance(beanName, mbd, args);

在这里插入图片描述

2.3.3,bean的后置处理器(实例化后)

在实例化之后,这里又会进行一个后置处理器的调用,这里会将一些 @AutoWired @Value 的注解进行预解析

synchronized (mbd.postProcessingLock) {
	if (!mbd.postProcessed) {
		try {
			//进行后置处理 @AutoWired @Value的注解的预解析
			applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Post-processing of merged bean definition failed", ex);
		}
		mbd.postProcessed = true;
	}
}
2.3.4,属性填充

接下来就是进入属性填充的阶段,里面通过调用这个 populateBean 方法进行属性填充

//属性赋值 给我们的属性进行赋值(调用set方法进行赋值)
populateBean(beanName, mbd, instanceWrapper);

在属性填充的方法中,会通过这个InstantiationAwareBeanPostProcessor类判断是否有一个 postProcessAfterInstantiation 的后置处理器,和实例化前的前置处理器功能类似,这种接口都是spring留给我们开发人员去自定义扩展的一些接口,改功能为实例化后,属性注入前的一个扩展点

if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
	//获取容器中的所有的BeanPostProcessor
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		//判断我们的后置处理器是不是InstantiationAwareBeanPostProcessor
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			//进行强制转化
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			//若存在后置处理器给我们属性赋值了,那么返回false 可以来修改我们的开关变量,就不会走下面的逻辑了
			if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
				// 返回值为是否继续填充 bean
				// postProcessAfterInstantiation:如果应该在 bean上面设置属性则返回 true,否则返回 false
				// 一般情况下,应该是返回true 。
				// 返回 false 的话,将会阻止在此 Bean 实例上调用任何后续的 InstantiationAwareBeanPostProcessor 实
				continueWithPropertyPopulation = false;
				break;
			}
		}
	}
}

下面这段代码就是依赖注入的功能,判断注入的类型是通过type类型还是通过name的类型输入属性

if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
	//把PropertyValues封装成为MutablePropertyValues
	MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
	//根据bean的属性名称注入
	if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
		autowireByName(beanName, mbd, bw, newPvs);
	}
	//根据bean的类型进行注入
	if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
		autowireByType(beanName, mbd, bw, newPvs);
	}
	//把处理过的 属性覆盖原来的
	pvs = newPvs;
}

代码往下执行又可以看到一个InstantiationAwareBeanPostProcessor对象的 ,给开发人员一些扩展接口,用于给开发者在@Autoware等属性中提前进行初始赋值

在这里插入图片描述

2.3.5,初始化

最后一个步骤就是进行初始化,上面已经进行了对象的实例化,属性填充,那么最后一步就剩下初始化了。

//进行对象初始化操作(在这里可能生成代理对象)
exposedObject = initializeBean(beanName, exposedObject, mbd);

直接查看这个 initializeBean 方法,可以发现初始化方法中主要有四个步骤:

  • 一个是判断是否实现Aware接口的回调,比如是否实现 BeanNameAware、BeanFactoryAware 接口,还有一些环境的aware,以及Resource资源的aware,事件发布器的aware等
  • 初始化前会调用bean的后置处理器,用于加载一些 @PostConstruct 等注解
  • 然后就是进行调用初始化的方法,
  • 最后执行一个调用bean的后置处理器的一个方法,比如处理所有aop是否需要执行动态代理等

在这里插入图片描述

2.4,销毁

依旧是在这个doCreateBean方法的最后面,有一个销毁的方法 registerDisposableBeanIfNecessary

registerDisposableBeanIfNecessary(beanName, bean, mbd);

由于这一块用的相对较少,因此不做过多的分析

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

huisheng_qaq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值