Spring源码核心篇整体栏目
内容 | 链接地址 |
---|---|
【一】Spring的bean的生命周期 | https://zhenghuisheng.blog.csdn.net/article/details/143441012 |
如需转载,请附上链接:https://blog.csdn.net/zhenghuishengq/article/details/143441012
springbean_10">一,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启动上下文,这里直接选用注解的方式启动上下文
java">AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
这个对象的继承关系如下,继承了 GenericApplicationContext 类,实现了 AnnotationConfigRegistry 接口
java">public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {}
在初始化这个 AnnotationConfigApplicationContext 对象之后,可以发现这个对象是 BeanFactory 的一个实现类,也就是说在初始化这个context上下文之前,还会先初始化一个 BeanFactory 的工厂,并且BeanFactory工厂有的功能context上下文都有,context就是一个BeanFactory的一个具体实现
接下来以下面这个包路径的源码进行分析,如分析一段service包下面的所有注解是如何注册到spring中生产bean对象,AnnotationConfigApplicationContext 其他的几个构造方法可以先不看
java">public AnnotationConfigApplicationContext(String... basePackages) {this(); //注册一个读取器和扫描器,也可以先不看scan(basePackages); //扫描包路径refresh(); //spring中最核心的方法,refresh方法
}
1.2,核心doScan方法
然后直接分析这个scan方法,一直往下点,可以看到一个 doScan 方法,就是扫描的核心方法,然后会循环的寻找包路径集合,最后回去找每一个路径下面的有 @Component 注解的bean,然后将bean生成一个 BeanDefinition
java">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) {//找到候选的ComponentsSet<BeanDefinition> candidates = findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {//拿到元数据解析器,可以获取类中所有信息ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());//设置我们的beanNameString beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);//这是默认配置 autowire-candidateif (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对象被实例化
java">@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定义作用域
java">ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
然后就是判断类是否懒加载,是否加了 @Dependson注解等,Dependson注解主要用于依赖关系,比如A上面加了一个依赖B的注解,那么在加载A实例前需要先加载B实例,这种方式造成的循环依赖解决不了,只能手动的避免
java">if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
1.5,Bedefinition存入BeanDefinitionMap
最后会先判断当前bean定义是否已经存在于容器中,如果不存在的话,把我们解析出来的组件bean定义注册到spring的IOC容器中
java">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 方法中,可以发现是直接通过一个工具类进行了注册
java">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的方法
java">finishBeanFactoryInitialization(beanFactory);
在这个方法中,会有一个专门实例化单例bean的方法 preInstantiateSingletons
java">protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {//实例化剩余的单实例beanbeanFactory.preInstantiateSingletons();
}
在这个实例化单例bean的方法中,会遍历全部扫描拿到的单例beanDefinition,做以下流程:
- 先判断这个beanDefinition是否为抽象的、单例的或者是否为懒加载的
- 再次判断这个beanDefinition是否为工厂bean,是的话则需要特殊处理转化成对应的bean
- 最后调用这个getBean方法去创建对应的实例,有这个实例则直接获取,无则创建
2.2,doGetBean
接下来就是进入bean工厂创建bean的方法,在进入上面的getBean方法之后,里面可以看到这个真正去创建bean的方法 doGetBean 方法
java">@Override
public Object getBean(String name) throws BeansException {//真正的获取bean的逻辑return doGetBean(name, null, null, false);
}
如下图所示,其部分流程如下:
- 首先第一步就是获取到这个bean的别名,如果有别名则获取到别名,没有则用当前bean的名字
- 随后去单例池的缓存中获取对象,默认绝大多数的对象都是单例对象
首先刚进来这个单例池里面肯定是没有对象的,因为还未初始化放到单例池里面,因此看后面的else逻辑。下面这段代码的逻辑也比较简单,就是判断这个BeanDefinition是否存在于单前的BeanFactory中,如果不存在,那么就去父工厂的BeanFactory中去获取
java">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先创建出来,这个注解方式避免不了循环依赖,只能手动解决
java">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的beangetBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}
}
2.3,createBean
在对上面的那些东西进行校验完成之后,接下来就是真正的进入创建单例bean的方法,在单例方法中,首先会判断是否为单例bean,然后最终调用这个 createBean 方法进行bean的创建
java">//创建单例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等注解,最后进行一个动态代理,这一步就是实例化前的操作
java">@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中,可以在里面看到一下这段代码,将这个对应的切面解析并保存到缓存中
java">//bean的前置处理器
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
//bean的后置处理器
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
2.3.2,实例化bean
在上面的getBean方法中继续往下走,可以发现一个真正的去创建实例bean的doCreateBean方法
java">try {/*** 该步骤是我们真正的创建我们的bean的实例对象的过程*/Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
方法如下图,首先会将这个Bean进行一个 BeanWrapper的包装,然后调用 createBeanInstance 进行bean的实例化,在进行实例化时,会对实例化的方式进行推断,如是否用构造方法、工厂方法等
java">instanceWrapper = createBeanInstance(beanName, mbd, args);
2.3.3,bean的后置处理器(实例化后)
在实例化之后,这里又会进行一个后置处理器的调用,这里会将一些 @AutoWired @Value 的注解进行预解析
java">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 方法进行属性填充
java">//属性赋值 给我们的属性进行赋值(调用set方法进行赋值)
populateBean(beanName, mbd, instanceWrapper);
在属性填充的方法中,会通过这个InstantiationAwareBeanPostProcessor类判断是否有一个 postProcessAfterInstantiation 的后置处理器,和实例化前的前置处理器功能类似,这种接口都是spring留给我们开发人员去自定义扩展的一些接口,改功能为实例化后,属性注入前的一个扩展点
java">if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {//获取容器中的所有的BeanPostProcessorfor (BeanPostProcessor bp : getBeanPostProcessors()) {//判断我们的后置处理器是不是InstantiationAwareBeanPostProcessorif (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的类型输入属性
java">if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {//把PropertyValues封装成为MutablePropertyValuesMutablePropertyValues 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,初始化
最后一个步骤就是进行初始化,上面已经进行了对象的实例化,属性填充,那么最后一步就剩下初始化了。
java">//进行对象初始化操作(在这里可能生成代理对象)
exposedObject = initializeBean(beanName, exposedObject, mbd);
直接查看这个 initializeBean 方法,可以发现初始化方法中主要有四个步骤:
- 一个是判断是否实现Aware接口的回调,比如是否实现 BeanNameAware、BeanFactoryAware 接口,还有一些环境的aware,以及Resource资源的aware,事件发布器的aware等
- 初始化前会调用bean的后置处理器,用于加载一些 @PostConstruct 等注解
- 然后就是进行调用初始化的方法,
- 最后执行一个调用bean的后置处理器的一个方法,比如处理所有aop是否需要执行动态代理等
2.4,销毁
依旧是在这个doCreateBean方法的最后面,有一个销毁的方法 registerDisposableBeanIfNecessary
java">registerDisposableBeanIfNecessary(beanName, bean, mbd);
由于这一块用的相对较少,因此不做过多的分析