解析完配置后,来看下 bean 是如何加载的java
既然咱们 Spring
辛辛苦苦将 bean
进行了注册,固然须要拿出来进行使用,在使用以前还须要通过一个步骤,就是 bean
的加载。git
在第一篇笔记提到了,完成 bean
注册到 beanDefinitionMap
注册表后,还调用了不少后处理器的方法,其中有一个方法 finishBeanFactoryInitialization()
,注释上面写着 Instantiate all remaining (non-lazy-init) singletons
,意味着非延迟加载的类,将在这一步实例化,完成类的加载。github
而咱们使用到 context.getBean("beanName")
方法,若是对应的 bean
是非延迟加载的,那么直接就能拿出来进行使用,而延迟加载的 bean
就须要上面的步骤进行类的加载,加载完以后才能进行使用~spring
下面一块儿来看下这两个步骤中, bean
是如何进行加载的。缓存
咱们的代码分析都是围绕着这个方法,请同窗们提早定位好位置:bash
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean多线程
这个 bean
加载的代码量是有点多的,已经超过 100 行,因此整理了时序图,但愿能对加载流程有个清晰的概览:并发
这个时序图介绍了 bean
加载的大致流程,还有不少细节没在图中进行展现。咱们先对总体流程有个了解,而后跟着代码一块儿深刻分析吧。mvc
再提示一下:因为代码量不少,每次贴大段代码看起来会比较吃力,因此展现的是我认为的关键代码,下载项目看完整注释,跟着源码一块儿分析~app
在分析加载流程以前,有个前置概念要了解下,在通常状况下,Spring
是经过反射机制利用 bean
的 class
属性指定实现类来实例化 bean
。
引用书本:
在某些状况下,实例化
bean
比较复杂,例若有多个参数的状况下,传统方式须要在配置文件中,写不少配置信息,显得不太灵活。在这种状况下,可使用Spring
提供的FactoryBean
接口,用户能够经过实现该接口定制实例化bean
的逻辑。
FactoryBean
接口定义了三个方法:
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
复制代码
主要讲下用法吧:
当配置文件中的
<bean>
的class
属性实现类是FactoryBean
时,经过getBean()
方法返回的不是FactoryBean
自己,而是FactoryBean#getObject()
方法返回的对象。
使用 demo
代码请看下图:
扩展 FactoryBean
以后,须要重载图中的两个方法,经过泛型约定返回的类型。在重载的方法中,进行本身个性化的处理。
在启动类 Demo
,经过上下文获取类的方法 context.getBean("beanName")
,使用区别是 beanName
是否使用 & 前缀,若是有没有 & 前缀,识别到的是 FactoryBean.getObject 返回的 car
类型,若是带上 & 前缀,那么将会返回 FactoryBean
类型的类。
验证和学习书中的概念,最快的方式是运行一遍示例代码,看输出结果是否符合预期,因此参考书中的例子,本身手打代码,看最后的输出结果,发现与书中说的一致,同时也加深了对 FactoryBean
的了解。
为何要先讲 BeanFactory
这个概念呢?
从时序图看,在 1.5 那个步骤,调用了方法:
org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
在这一步中,会判断 sharedInstance
类型,若是属于 FactoryBean
,将会调用用户自定义 FactoryBean
的 getObject()
方法进行 bean
初始化。
实例化的真正类型是 getObjectType()
方法定义的类型,不是 FactoryBean
原来自己的类型。最终在容器中注册的是 getObject()
返回的 bean
。
提早讲了这个概念,但愿你们在最后一步时不会对这个有所迷惑。
// Eagerly check singleton cache for manually registered singletons.
// 检查缓存中或者实例工厂是否有对应的实例或者从 singletonFactories 中的 ObjectFactory 中获取
Object sharedInstance = getSingleton(beanName);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
// 检查缓存中是否存在实例
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 记住,公共变量都须要加锁操做,避免多线程并发修改
synchronized (this.singletonObjects) {
// 若是此 bean 正在加载则不处理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 当某些方法须要提早初始化,调用 addSingletonFactory 方法将对应的
// objectFactory 初始化策略存储在 singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
复制代码
单例模式在代码设计中常常用到,在 Spring
中,同一个容器的单例只会被建立一次,后续再获取 bean
直接从单例缓存 singletonObjects
中进行获取。
并且由于单例缓存是公共变量,因此对它进行操做的时候,都进行了加锁操做,避免了多线程并发修改或读取的覆盖操做。
还有这里有个 earlySingletonObjects
变量,它也是单例缓存,也是用来保存 beanName
和 建立 bean
实例之间的关系。
与 singletonFactories
不一样的是,当一个单例 bean
被放入到这 early
单例缓存后,就要从 singletonFactories
中移除,二者是互斥的,主要用来解决循环依赖的问题。(循环依赖下一篇再详细讲吧)
在 getBean
方法中,getObjectForBeanInstance
是个高频方法,在单例缓存中得到 bean
仍是 根据不一样 scope
策略加载 bean
,都有这个方法的出现,因此结合刚才说的 BeanFactory
概念,一块儿来看下这个方法作了什么。
org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
// 返回对应的实例,有时候存在诸如 BeanFactory 的状况并非直接返回实例自己
// 而是返回指定方法返回的实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
复制代码
具体方法实现,搜索 注释 4.6 看代码中的注释吧:
交代一下这个方法的流程:
bean
类型:判断是不是工厂 bean
FactoryBean
不作处理bean
进行转换FactoryBean
类型:委托给 getObjectFromFactoryBean
方法进行处理。在这个方法中,对工厂 bean
有特殊处理,处理方法跟上面提到的 FactoryBean
使用同样,最终获取的是 FactoryBean.getObject()
方法返回的类型。
对于第四个步骤,委托给 getObjectFromFactoryBean
方法进行处理不深刻分析,但里面有三个方法值得一说:
// 单例操做,前置操做
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
// 单例模式,后置操做
afterSingletonCreation(beanName);
}
复制代码
代码中在类的加载时,有前置操做和后置操做,以前在第一篇笔记看过,不少前置和后置操做都是空方法,等用户自定义扩展用的。
但在这里的不是空方法,在两个方法是用来保存和移除类加载的状态,是用来对循环依赖进行检测的。
同时,这两个方法在不一样 scope
加载 bean
时也有使用到,也是个高频方法。
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
复制代码
这是一个执行后处理的方法,我接触的很少,先记下概念:
Spring 获取 bean 的规则中有一条:尽量保证全部 bean 初始化后都会调用注册的 BeanPostProcessor 的 postProcessAfterInitialization 方法进行处理。在实际开发中,能够针对这个特性进行扩展。
如今来到时序图中的 1.3 步骤:
// Create bean instance. 建立 bean 实例
// singleton 单例模式(最常使用)
if (mbd.isSingleton()) {
// 第二个参数的回调接口,接口是 org.springframework.beans.factory.ObjectFactory#getObject
// 接口实现的方法是 createBean(beanName, mbd, args)
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
// 省略了 try / catch
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
复制代码
来看 getSingleton
方法作了什么:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
// 注释 4.7 全局变量,加锁
synchronized (this.singletonObjects) {
// 检查是否已经被加载了,单例模式就是能够复用已经建立的 bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 初始化前操做,校验是否 beanName 是否有别的线程在初始化,并加入初始化状态中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
// 初始化 bean,这个就是刚才的回调接口调用的方法,实际执行的是 createBean 方法
singletonObject = singletonFactory.getObject();
newSingleton = true;
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 初始化后的操做,移除初始化状态
afterSingletonCreation(beanName);
if (newSingleton) {
// 加入缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
复制代码
来梳理一下流程:
beanName
的加载状态bean
bean
过程当中所记录到的各类辅助状态对于第二步和第四步,在前面已经提到,用来记录 bean
的加载状态,是用来对 循环依赖 进行检测的,这里先略过不说。
关键的方法在于第三步,调用了 ObjectFactory
的 getObject()
方法,实际回调接口实现的是 createBean()
方法,须要往下了解,探秘 createBean()
。
bean
对于书中,有句话说的很到位:
在
Spring
源码中,一个真正干活的函数实际上是以do
开头的,好比doGetBean
、doGEtObjectFromFactoryBean
,而入口函数,好比getObjectFromFactoryBean
,实际上是从全局角度去作统筹工做。
有了这个概念后,看以后的 Spring
源码,都知道这个套路,在入口函数了解总体流程,而后重点关注 do
开头的干活方法。
按照这种套路,咱们来看这个入口方法 createBean()
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
RootBeanDefinition mbdToUse = mbd;
// 有道翻译:确保此时bean类已经被解析,而且克隆 bean 定义,以防动态解析的类不能存储在共享合并 bean 定义中。
// 锁定 class,根据设置的 class 属性或者根据 className 来解析 Class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
// 验证及准备覆盖的方法
mbdToUse.prepareMethodOverrides();
// 让 beanPostProcessor 有机会返回代理而不是目标bean实例。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
// 短路操做,若是代理成功建立 bean 后,直接返回
return bean;
}
// 建立 bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
复制代码
先来总结这个流程:
lookup-method
和 replaced-method
属性,而后这两个配置的加载将会统一存放在 beanDefinition
中的 methodOverrides
属性里。下面来说下这几个主要步骤
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exists.
if (hasMethodOverrides()) {
Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
synchronized (overrides) {
for (MethodOverride mo : overrides) {
// 处理 override 属性
prepareMethodOverride(mo);
}
}
}
}
复制代码
能够看到,获取类的重载方法列表,而后遍历,一个一个进行处理。具体处理的是 lookup-method
和 replaced-method
属性,这个步骤解析的配置将会存入 beanDefinition
中的 methodOverrides
属性里,是为了待会实例化作准备。
若是 bean
在实例化时,监测到 methodOverrides
属性,会动态地位当前 bean
生成代理,使用对应的拦截器为 bean
作加强处理。
(我是不推荐在业务代码中使用这种方式,定位问题和调用都太麻烦,一不当心就会弄错=-=)
// 让 beanPostProcessor 有机会返回代理而不是目标bean实例。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
// 短路操做,若是代理成功建立 bean 后,直接返回
return bean;
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 执行前置拦截器的操做
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 执行后置拦截器的操做
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
复制代码
在 doCreateBean
方法前,有一个短路操做,若是后处理器成功,将会返回代理的 bean
。
在 resolveBeforeInstantiation
方法中,在确保 bean
信息已经被解析完成,执行了两个关键方法,从注释中看到,一个是前置拦截器的操做,另外一个就是后置拦截器的操做。
若是第一个前置拦截器实例化成功,就已经将单例 bean
放入缓存中,它不会再经历普通 bean
的建立过程,没有机会进行后处理器的调用,因此在这里的第二个步骤,就是为了这个 bean
也能应用后处理器的 postProcessAfterInitialization
方法。
终于到了关键的干活方法:doGetBean
。在经过上一个方法校验,没有特定的前置处理,因此它是一个普通 bean
, 常规 bean
进行建立在 doGetBean
方法中完成。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 注释 4.8 根据指定 bean 使用对应的策略建立新的实例 例如跟进方法去看,有工厂方法,构造函数自动注入,简单初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 容许后处理程序修改合并的bean定义
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
// 是否须要提早曝光,用来解决循环依赖时使用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 第二个参数是回调接口,实现的功能是将切面动态织入 bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
// 对 bean 进行填充,将各个属性值注入
// 若是存在对其它 bean 的依赖,将会递归初始化依赖的 bean
populateBean(beanName, mbd, instanceWrapper);
// 调用初始化方法,例如 init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
// earlySingletonReference 只有在检测到有循环依赖的状况下才 不为空
if (earlySingletonReference != null) {
if (exposedObject == bean) {
// 若是 exposedObject 没有在初始化方法中被改变,也就是没有被加强
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
// 检查依赖
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// bean 建立后,它所依赖的 bean 必定是已经建立了
// 在上面已经找到它有依赖的 bean,若是 actualDependentBeans 不为空
// 表示还有依赖的 bean 没有初始化完成,也就是存在循环依赖
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
}
// Register bean as disposable.
// 根据 scope 注册 bean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}
复制代码
看到这么长的代码,感受有点头晕,因此先来梳理这个方法的流程:
从上面流程能够看出,这个方法作了不少事情,以致于代码超过了 100 多行,给人的阅读体验差,因此尽可能仍是拆分小方法,在入口方法尽可能简洁,说明作的事情,具体在小方法中完成。
由于这个建立过程的代码不少和复杂,我挑重点来理解和学习,详细的还有待深刻学习:
在上面第二个步骤,作的是实例化 bean
,而后返回 BeanWrapper
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
// Shortcut when re-creating the same bean...
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) {
// 实际解析的是 org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor
// 构造函数自动注入(若是参数有不少个,在匹配构造函数可复杂了,不敢细看=-=)
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 使用默认的构造函数
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring? 须要根据参数解析构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 构造函数注入
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor. 没有特殊的处理,使用默认构造函数构造
return instantiateBean(beanName, mbd);
}
复制代码
大体介绍功能:
org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor
在这个流程中,经过两种方式,一种是工厂方法,另外一种就是构造函数,将传进来的 RootBeanDefinition
中的配置二选一辈子成 bean
实例
具体的不往下跟踪,来看下一个步骤
// 是否须要提早曝光,用来解决循环依赖时使用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 第二个参数是回调接口,实现的功能是将切面动态织入 bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
复制代码
关键方法是 addSingletonFactory
,完成的做用:在 bean
初始化完成前将建立实例的 ObjectFactory
加入单例工厂
一开始就讲过, ObjectFactory
是建立对象时使用的工厂。在对象实例化时,会判断本身依赖的对象是否已经建立好了,判断的依据是查看依赖对象的 ObjectFactory
是否在单例缓存中,若是没有建立将会先建立依赖的对象,而后将 ObjectFactory
放入单例缓存。
这时若是有循环依赖,须要提早对它进行暴露,让依赖方找到并正常实例化。
循环依赖解决方案在下一篇再细讲吧。
这也是个高频方法,在初始化的时候要对属性 property
进行注入,贴一些代码片断:
populateBean(beanName, mbd, instanceWrapper);
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 给 awareBeanPostProcessor 后处理器最后一次机会,在属性设置以前修改bean的属性
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
...
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
...
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
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);
PropertyDescriptor[] filteredPds = null;
// 从 beanPostProcessors 对象中提取 BeanPostProcessor 结果集,遍历后处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
...
}
// 在前面也出现过,用来进行依赖检查
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
checkDependencies(beanName, mbd, filteredPds, pvs);
// 将属性应用到 bean 中,使用深拷贝,将子类的属性一并拷贝
applyPropertyValues(beanName, mbd, bw, pvs);
}
复制代码
因为代码太长,感兴趣的小伙伴定位到 注释 4.11 位置查看吧
介绍一下处理流程:
InstantiationAwareBeanPostProcessor
处理器的 postProcessAfterInstantiation
方法,判断控制程序是否继续进行属性填充byName/byType
),提取依赖的 bean
,统一存入 PropertyValues
中BeanPostProcessor
和 依赖检查:InstantiationAwareBeanPostProcessor
处理器的 postProcessProperties
方法,对属性获取完毕填充前,对属性进行再次处理。checkDependencies
方法来进行依赖检查PropertyValues
中的属性填充至 BeanWrapper
中。在这个方法中,根据不一样的注入类型进行属性填充,而后调用后处理器进行处理,最终将属性应用到 bean
中。
这里也不细说,继续往下走,看下一个方法
在配置文件中,在使用 <bean>
标签时,使用到了 init-method
属性,这个属性的做用就是在这个地方使用的:bean
实例化前,调用 init-method
指定的方法来根据用户业务进行相应的实例化。来看下入口方法 initializeBean
:
// 调用初始化方法,例如 init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 注释 4.12 securityManage 是啥,不肯定=-=
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 若是没有 securityManage,方法里面校验了 bean 的类型,须要引用 Aware 接口
// 对特殊的 bean 处理:Aware/ BeanClassLoader / BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 熟悉么,后处理器又来了
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 激活用户自定义的 init-method 方法
invokeInitMethods(beanName, wrappedBean, mbd);
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
复制代码
这个方法主要是用来进行咱们设定的初始化方法的调用,不过在方法内部,还作了其它操做,因此一块儿来说下流程:
一、激活 Aware 方法
Spring
中提供了一些 Aware
接口,实现了这个接口的 bean
,在被初始化以后,能够取得一些相对应的资源,例如 BeanFactoryAware
,在初始化后, Spring
容器将会注入 BeanFactory
的实例。因此若是须要获取这些资源,请引用 Aware
接口。
二、执行后处理器
相信这个你们已经不陌生了,咱们能够在诸如 PostProcessor
等后处理器里面自定义,实现修改和扩展。例如 BeanPostProcessor
类中有 postProcessBeforeInitialization
和 postProcessAfterInitialization
,能够对 bean
加载先后进行逻辑扩展,能够将它理解成切面 AOP
的思想。
三、激活自定义的 init 方法
这个方法用途很明显,就是找到用户自定义的构造函数,而后调用它。要注意的是,若是 bean
是 InitializingBean
类型话,须要调用 afterPropertiesSet
方法。
执行顺序是先 afterPropertiesSet
,接着才是 init-method
定义的方法。
这是 Spring
提供销毁方法的扩展入口,Spring
爸爸将咱们能考虑和想扩展的口子都给预留好。除了经过 destroy-method
属性配置销毁方法外,还能够注册后处理器 DestructionAwareBeanPostProcessor
来统一处理 bean
的销毁方法:
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// 单例模式
// 注册 DisposableBean
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
复制代码
这里就是往不一样的 scope
下, 进行 disposableBean
的注册。
本篇笔记总结了类加载的过程,结合时序图和代码分析,但愿对它能有一个更深的了解。
同时对代码编写也有一点感触:
从一开始看 Spring
源码的时候,就惊叹于它代码的整洁和逻辑清晰,入口方法展现须要作的事情,而后工做具体逻辑细分,体现了代码设计者的高超设计。
因此在看到有几个方法超过 100 行,心中小小吐槽了一下,看来我跟大佬们写的代码也有共同点,那就是还能够进行优化哈哈哈~
我截取的代码片断,因为篇幅缘由,有些逻辑判断和日志处理都给摘掉了,可是日志管理是很重要的一环,在关键地方打印日志,在以后排查问题和分析数据都会有帮助。
若是懒得打印日志,在关键的地方没有打印日志,即使出现了问题,也不知道从何查起,致使问题的缘由迟迟没法暴露,形成用户的投诉,那就得不偿失了。
因为我的技术有限,若是有理解不到位或者错误的地方,请留下评论,我会根据朋友们的建议进行修正
spring-analysis-note 码云 Gitee 地址
spring-analysis-note Github 地址
Spring 源码深度解析 / 郝佳编著. -- 北京 : 人民邮电出版社