共计 12403 个字符,预计需要花费 32 分钟才能阅读完成。
bean 的加载(二)
之前文章次要对 getBean 办法进行简略的介绍,和 FactoryBean 的作用,以及是如何从缓存中获取 bean。本文持续解说 bean 的加载流程。
从 bean 的实例中获取对象
在 getBean 办法里,getObjectForBeanInstance()
是个罕用的办法,无论是从缓存中获取 bean 还是依据不同 scope 策略来加载 bean。总而言之,咱们在获取到 bean 实例后第一步就是调用这个办法来检测正确性,其实就是检测以后 bean 是否为 FactoryBean 类型的 bean,如果是则调用 FactoryBean 实例的 getObject()作为返回值。
须要留神的是无论是缓存中获取到的 bean 还是通过 scope 策略加载的 bean 都是 原始的 bean 状态,咱们须要的是工厂 bean 中定义 factory-method 办法中返回的 bean,而 getObjectForBeanInstance 办法就是实现这个工作的。
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 如果指定的 name 是工厂相干以 "&" 为前缀, 并且 beanInstance 又不是 FactoryBean 则校验不通过
if (BeanFactoryUtils.isFactoryDereference(name)) {if (beanInstance instanceof NullBean) {return beanInstance;}
if (!(beanInstance instanceof FactoryBean)) {throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {mbd.isFactoryBean = true;}
return beanInstance;
}
// 当初咱们有了这个 bean 实例, 这个实例可能是 FactoryBean, 也可能是失常的 bean
// 如果是 FactoryBean 的话, 咱们应用它创立实例, 但如果是用户想要间接获取工厂实例而不是工厂的 getObject 办法则须要在 BeanName 前加上 "&"
if (!(beanInstance instanceof FactoryBean)) {return beanInstance;}
// 加载 FactoryBean
Object object = null;
if (mbd != null) {mbd.isFactoryBean = true;}
else {
// 尝试从缓存中加载 bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 执行到这里表明 beanInstance 肯定是一个 FactoryBean
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// containsBeanDefinition 检测 BeanDefinitionMap 中也就是在所有一键加载的类中检测是否定义 beanName
if (mbd == null && containsBeanDefinition(beanName)) {
// 将 GenericBeanDefinition 转换为 RootBeanDefinition, 如果指定 BeanName 是子 bean 的话同时会合并父类的属性
mbd = getMergedLocalBeanDefinition(beanName);
}
// 是否是用户定义的而不是应用程序自身定义的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
咱们先看一下 getObjectForBeanInstance 次要做了什么:
- 对 FactoryBean 正确性进行验证
- 对非 FactoryBean 不作任何解决
- 对 bean 进行转换
- 将从 Factory 中解析 bean 的工作委托给了
getObjectFromFactoryBean
。
该段代码大多都是辅助代码,真正的外围代码委托给了getObjectFromFactoryBean
。
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {if (factory.isSingleton() && containsSingleton(beanName)) {synchronized (getSingletonMutex()) {Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 重点办法 doGetObjectFromFactoryBean
object = doGetObjectFromFactoryBean(factory, beanName);
//... 省略
}
else {
// 重点办法 doGetObjectFromFactoryBean
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
这段代码就是返回的 bean 如果是单例的则须要保障全局惟一,也正因为是单例的所以不用反复创立,能够用缓存来进步性能。
咱们进入 doGetObjectFromFactoryBean
办法中。
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
// 是否须要权限校验
if (System.getSecurityManager() != null) {AccessControlContext acc = getAccessControlContext();
try {object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {throw pae.getException();
}
}
else {// 间接调用 getObject 办法(重点)
object = factory.getObject();}
}
catch (FactoryBeanNotInitializedException ex) {throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();}
return object;
}
在该办法中,咱们终于看到了想要看到的代码,也就是object = factory.getObject()
。之前咱们曾经讲过了 FactoryBean 的调用办法,如果 bean 是 FactoryBean 类型,则当提取 bean 时提取的并不是 factoryBean 而是 factoryBean 的 getObject 办法的返回值。
获取单例
之前咱们说过如果缓存中不存在曾经加载的 bean 则须要重头开始 bean 的加载,在 Spring 中应用 getSingleton 的重载办法实现了 bean 的加载过程。
getBean 办法:
// 实例化依赖的 bean 后就能够实例化 mbd 自身了
// 如果 BeanDefinition 为单例
if (mbd.isSingleton()) {
// 创立 Bean 实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, () -> {
try {return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// 从单例缓存中删除 bean 实例
// 因为单例模式下为了解决循环依赖,可能它曾经存在了,所以将其销毁
destroySingleton(beanName);
throw ex;
}
});
// 如果是一般 bean,间接返回,如果是 FactoryBean,则返回它的 getObject
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
进入 getSingleton 办法:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");
// 加锁
synchronized (this.singletonObjects) {
// 首先查看对应的 bean 是否曾经加载过,
Object singletonObject = this.singletonObjects.get(beanName);
// 如果为空则须要进行 singleton 的 bean 初始化
if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction" +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {logger.debug("Creating shared instance of singleton bean'" + beanName + "'");
}
// 代码(1)
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 通过回调形式获取 bean 实例。singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {throw ex;}
}
catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}
// 代码(2)
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 退出缓存 代码(3)addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
上述代码应用了回调办法,在单例创立的前后做了些筹备及解决操作,而真正获取单例 bean 的办法是在 ObjectFactory 类型的实例 singletonFactory 中。咱们先看一下 getSingleton 办法次要做了什么:
- 查看缓存是否曾经加载过
- 若没有加载,则记录 beanName 为正在加载状态
- 加载单例前记录加载状态,代码(1)
protected void beforeSingletonCreation(String beanName) {if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {throw new BeanCurrentlyInCreationException(beanName);
}
}
这个办法次要做的就是记录加载状态,this.singletonsCurrentlyInCreation.add(beanName)
将以后正要创立的 bean 记录在缓存中,这样就能够对循环依赖进行检测。
- 获取 bean 实例
- 调用加载单例后的解决办法,代码(2)
protected void afterSingletonCreation(String beanName) {if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {throw new IllegalStateException("Singleton'" + beanName + "'isn't currently in creation");
}
}
和上述相似,只是这里是从缓存中移除 bean 的正在加载状态。
- 将 bean 退出缓存,并删除加载 bean 过程中所记录的各种辅助状态。
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
- 返回处理结果
当初咱们曾经理解了 bean 的逻辑架构,然而 bean 的加载逻辑是在传入 ObjectFactory 类型的参数 singletonFactory 中定义的。
// 创立 Bean 实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, () -> {
try {return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// 从单例缓存中删除 bean 实例
// 因为单例模式下为了解决循环依赖,可能它曾经存在了,所以将其销毁
destroySingleton(beanName);
throw ex;
}
});
咱们进入 createBean 办法中持续查看。
筹备创立 bean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean'" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// 锁定 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.
// 验证及筹备笼罩的办法
try {mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 给 BeanPostProcessors 一个机会来返回代理用于代替真正的实例
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {return bean;}
}
catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {// 代码(1)
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean'" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
- 依据设置的 class 属性或者依据 className 来解析 Class
- 对 override 属性进行标记及验证
咱们晓得在 Spring 的配置中并没有相似于 override-methdo 之类的配置,那么该办法的作用是什么?
咱们之前说过 Spring 配置中存在 lookup-method 和 replace-method 的,这两个配置的加载就是将配置对立寄存在 BeanDefinition 中的 methodOverrides 属性中,而这个函数其实也就是针对这两个配置的。
- 利用初始化前的后处理器,解析指定 bean 是否存在初始化前的短路操作
- 创立 bean
咱们先看一下 override 属性标记及验证的逻辑实现
解决 override 属性
进入 prepareMethodOverrides 办法:
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exist and determine their overloaded status.
if (hasMethodOverrides()) {getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
}
}
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
// 获取对应类中对应办法名的个数
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException("Invalid method override: no method with name'" + mo.getMethodName() +
"'on class [" + getBeanClassName() + "]");
}
else if (count == 1) {
// Mark override as not overloaded, to avoid the overhead of arg type checking.
// 标记 MethodOverride 暂未被笼罩, 防止参数类型查看的开销
mo.setOverloaded(false);
}
}
方才说到 lookup-method 和 replace-method 两个配置性能是对立寄存在 BeanDefinition 中的 methodOverrides 属性中,这两个性能实现原理就是在 bean 实例化的时候如果检测到存在 methodOverrides 属性,就会动静地为以后 bean 生成代理并应用对应的拦截器对 bean 做加强解决。
须要提到的是,对于办法的匹配来说,如果一个类中有多个重载办法则须要依据参数类型进行匹配。如果类中只有办法只有一个那么就设置该办法没有被重载,这样在后续时候能够间接应用找到的办法,不须要进行办法的参数匹配验证,而且还能够提前对办法存在性进行验证,所谓一举两得。
实例化的前置解决
在调用 doCreateBean 之前,还应用了 resolveBeforeInstantiation(beanName, mbdToUse)办法对 BeanDefinition 中的属性做些前置解决。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {return bean;}
该段代码的重点就是这个 if 条件,当处理结果不为 null 的时候就会跳过后续 bean 的创立间接返回后果。咱们熟知的 AOP 性能就是基于这里判断的。
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) {// 代码(1)
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {// 代码(2)
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
该办法中的重点就是这两个办法:applyBeanPostProcessorsBeforeInstantiation、applyBeanPostProcessorsAfterInitialization。这两个办法实现都很简略,就是对后处理器中所有的 InstantiationAwareBeanPostProcessor 类型的后处理器进行 postProcessBeforeInstantiation 办法和 BeanPostProcessor 的 postProcessAfterInitialization 办法的调用。
1. 实例化前的后处理器利用
bean 的实例化前调用,也就是将 AbstractBeanDefinition 转换为 BeanWrapper 前的解决。给子类一个批改 BeanDefinition 的机会,也就是调用这个办法后 bean 就有可能产生变动,有可能是通过解决的代理 bean,也可能是 cglib 生成的。后续会具体介绍,当初只须要明确在 bean 实例化前会调用后处理器的办法进行解决。
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {return result;}
}
}
return null;
}
2. 实例化后的后处理器利用
Spring 的规定是在 bean 初始化后尽可能保障将注册的后处理器 postProcessAfterInitialization 办法利用到 bean 中,如果返回的 bean 不为空,则不须要再经验 bean 的创立过程。
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {return result;}
result = current;
}
return result;
}