Spring源码学习笔记(2)——Bean的加载
一. Bean加载的核心流程
前面大概分析了Spring读取解析配置文件,并加载BeanDefinition的过程。本节详细整理下Bean的加载过程。首先贴上核心代码
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { //提取对应的beanName final String beanName = transformedBeanName(name); Object bean; //首先检查缓存中或者实例工厂中是否有对应的的实例,因为在创建Singleton Bean的时候可能存在依赖注入的情况,而在创建依赖时,为了避免循环依赖,Spring创建Bean的原则是不等Bean创建完成,就会将创建Bean的ObjectFactory提早曝光,也就是将ObjectFactory加入到缓存中,一旦下一个Bean创建时需要依赖上一个Bean,就直接使用ObjectFactory //直接尝试从缓存获取或者从singletonFactories中ObjectFactory获取 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } } //返回创建的实例,如果是FactoryBean,则返回FactoryBean的getObject()方法创建的Bean bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //只有Singleton的Bean才解决循环依赖的问题,Prototype的Bean会抛出下面的异常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } //如果beanDefinitionMap中也就是已加载的Bean中不存在beanName,则递归地从parentBeanFactory中查找 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } } //如果是要加载Bean,而不仅仅是做类型检查,则需要记录 if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { //将存储XML配置文件的GenericBeanDefinition转换成RootBeanDefinition,如果指定beanName是子Bean的话,同时会合并父Bean的相关属性 final RootBeanDefinition本身 //Singleton模式的实例化mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); //如果存在依赖,则递归实例化依赖的Bean String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } //缓存依赖调用 registerDependentBean(dep, beanName); getBean(dep); } } //实例化所有依赖的Bean后,开始实例化RootBeanDefinition本身 //Singleton模式的实例化 if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //Prototype模式的实例化 else if (mbd.isPrototype()) { Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } //自定义Scope模式的实例化 else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } //检查需要的类型是否符合Bean的实际类型 if (requiredType != null && !requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }
当我们使用applicationContext.getBean(“beanName”)方法从容器中获取bean时,就会走到AbstractBeanFactory的doGetBean()方法,这是Spring容器加载bean的核心方法。下面对其核心流程进行介绍。
二. 提取实际的beanName
根据传入的name提取实际的beanName
protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); }
这里有两种情况:
传入的参数时FactoryBean的名称,会以&开头,这时需要调用BeanFactoryUtils
的方法解析,去除&返回FactoryBean的name;
public static String transformedBeanName(String name) { Assert.notNull(name, "'name' must not be null"); String beanName = name; while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } return beanName; }
传入的是别名alias,则需要SimpleAliasRegistry处理,根据注册的别名拿到实际的beanName。
public String canonicalName(String name) { String canonicalName = name; // Handle aliasing... String resolvedName; do { resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while (resolvedName != null); return canonicalName; }
三. 从缓存中获取单例Bean
在Spring中,Singleton类型的Bean只会创建一次,然后存放在缓存中,后面获取时就直接从缓存中获取。这里首先会尝试从缓存中获取Bean:
@Override @Nullable public Object getSingleton(String beanName) { //设置true表示允许早期依赖 return getSingleton(beanName, true); }
protected Object getSingleton(String beanName, boolean allowEarlyReference) { //如果缓存中存在实例,则直接返回 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { //如果缓存中实例为空,则先锁singletonObjects缓存,进行后续处理 synchronized (this.singletonObjects缓存,进行后续处理) { singletonObject = this.earlySingletonObjects.get(beanName); //如果此Bean之前正在被加载,则不处理 if (singletonObject == null && allowEarlyReference) { //当某些方法需要提前初始化时,会调用addSingletonFactory方法将其对应的ObjectFactory保存在singletonFactories中,也即保存其初始化策略 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); //如果存在预先初始化的ObjectFactory,则调用getObject()方法实例化Bean,并记录在缓存中。earlySingletonObjects与singletonFactories互斥 if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
上面方法中涉及到Spring Singleton相关的一些缓存:
- singletonObjects:用于缓存所有Singleton的Bean,
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
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);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}