Spring IOC(二)doGetBean方法源码分析

目录

    • doGetBean
      • 第1步:尝试从缓存中获取Bean
      • 第3步:Prototype类型Bean的循环依赖检查
      • 第5步:Depends-on依赖检查
      • 第6步:创建Singleton Bean
      • 第7步:创建Prototype Bean
      • 第9步:getObjectForBeanInstance判断是否为FactoryBean

以BeanFactory的getBean方法为入口,整理Bean的加载流程:

public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}

doGetBean

spring源码中真正的执行逻辑方法一般都是以do开头,看到doGetBean,那么真正的创建实例逻辑应是在此方法中:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

   final String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      if (logger.isTraceEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

      // Check if bean definition exists in this factory.
      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 if (requiredType != null) {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
         else {
            return (T) parentBeanFactory.getBean(nameToLookup);
         }
      }

      if (!typeCheckOnly) {
         markBeanAsCreated(beanName);
      }

      try {
         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         // Guarantee initialization of beans that the current bean depends on.
         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);
               try {
                  getBean(dep);
               }
               catch (NoSuchBeanDefinitionException ex) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
               }
            }
         }

         // Create bean instance.
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
                  // Explicitly remove instance from singleton cache: It might have been put there
                  // eagerly by the creation process, to allow for circular reference resolution.
                  // Also remove any beans that received a temporary reference to the bean.
                  destroySingleton(beanName);
                  throw ex;
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }

         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }

         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;
      }
   }

   // Check if required type matches the type of the actual bean instance.
   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.isTraceEnabled()) {
            logger.trace("Failed to convert bean '" + name + "' to required type '" +
                  ClassUtils.getQualifiedName(requiredType) + "'", ex);
         }
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
   }
   return (T) bean;
}

这个方法很长,大概功能包括了:

  1. 首先检查本地缓存,如果在缓存中已经存在此Bean,则返回缓存中的实例;
  2. 如果缓存中不存在,进行一些创建实例前的准备工作:
  3. 如果Bean的scope是Prototype1,则检查循环依赖;
  4. 如果当前BeanFactory中没有此BeanDefinition,且存在父BeanFactory,则从父BeanFactory中获取Bean;
  5. depends-on循环依赖检查,注意此处是值xml中配置的depends-on属性声明的依赖关系,而不是一般情况下我们所指的循环依赖问题;
  6. 创建Singleton类型的Bean
  7. 创建Prototype类型的Bean
  8. 创建其他scope类型的Bean
  9. (不管是第1步,还是第6、7、8步中,获取到实例后,都需要经过getObjectForBeanInstance方法再返回)

第1步:尝试从缓存中获取Bean

根据BeanName获取实例:

/**
	 * Return the (raw) singleton object registered under the given name.
	 * 

Checks already instantiated singletons and also allows for an early * reference to a currently created singleton (resolving a circular reference). * @param beanName the name of the bean to look for * @param allowEarlyReference whether early references should be created or not * @return the registered singleton object, or {@code null} if none found */ protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return (singletonObject != NULL_OBJECT ? singletonObject : null); }

这里涉及到了spring中对于单例Bean的 三级缓存 ,主要是用于解决 循环依赖 问题:

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

从缓存中获取的步骤是先访问一级缓存singletonObjects,如果存在则返回,没有则访问二级缓存earlySingletonObjects;
访问二级缓存,如果存在则返回,没有则访问三级缓存singletonFactories;
三级缓存中保存的是创建Bean的工厂,如果三级缓存存在,则调用其getObject方法得到Bean存入二级缓存,并且将Bean工厂从三级缓存中移除,也就是说从三级缓存移入到二级缓存中。

  • 一级缓存:单例对象缓存:当Bean已经被实例化、初始化之后,也就是完全创建完成后,会放入singletonObjects。
  • 二级缓存:早期单例对象缓存:它是一个中间的过渡缓存,保存已经被实例化,但没有被属性注入的早期暴露Bean。 当Bean没有完全创建完成时,一级缓存中当然没有,尝试二级缓存中获取,如果二级缓存中,但是在三级缓存中有此Bean的创建工厂,意味着可以得到这个Bean的早期暴露对象,将Bean的工厂从三级缓存中移除,放入二级缓存中。
  • 三级缓存:单例工厂缓存 :它保存的是可以创建Bean的工厂。

有关三级缓存机制和spring如何解决循环依赖的问题,下篇再详细叙述。

第3步:Prototype类型Bean的循环依赖检查

protected boolean isPrototypeCurrentlyInCreation(String beanName) {
		Object curVal = this.prototypesCurrentlyInCreation.get();
		return (curVal != null &&
				(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
	}

其中的prototypesCurrentlyInCreation是一个ThreadLocal的集合,保存了当前线程中,正在创建中的Prototype类型BeanName。结构为:

/** Names of beans that are currently in creation */
	private final ThreadLocal<Object> prototypesCurrentlyInCreation =
			new NamedThreadLocal<Object>("Prototype beans currently in creation");

当在此变量中得到了要创建的Bean,说明在当前线程中,此Bean正在创建中,但为什么又要创建呢,说明存在循环依赖了。如A与B互相依赖,A在创建过程中被存入prototypesCurrentlyInCreation,当检查到了依赖B,会先去创建B。当创建B的时候,发现依赖了A,由于是prototype类型的,所以A会被再次创建,再创建时发现A已经存在于prototypesCurrentlyInCreation中,表示两者循环依赖了。
所以明显,Bean加入到prototypesCurrentlyInCreation的时机,是实例创建前:

protected void beforePrototypeCreation(String beanName) {
		Object curVal = this.prototypesCurrentlyInCreation.get();
		if (curVal == null) {
			this.prototypesCurrentlyInCreation.set(beanName);
		}
		else if (curVal instanceof String) {
			Set<String> beanNameSet = new HashSet<String>(2);
			beanNameSet.add((String) curVal);
			beanNameSet.add(beanName);
			this.prototypesCurrentlyInCreation.set(beanNameSet);
		}
		else {
			Set<String> beanNameSet = (Set<String>) curVal;
			beanNameSet.add(beanName);
		}
	}

Bean从prototypesCurrentlyInCreation移除的时机,是实例创建后:

protected void afterPrototypeCreation(String beanName) {
		Object curVal = this.prototypesCurrentlyInCreation.get();
		if (curVal instanceof String) {
			this.prototypesCurrentlyInCreation.remove();
		}
		else if (curVal instanceof Set) {
			Set<String> beanNameSet = (Set<String>) curVal;
			beanNameSet.remove(beanName);
			if (beanNameSet.isEmpty()) {
				this.prototypesCurrentlyInCreation.remove();
			}
		}
	}

第5步:Depends-on依赖检查

depends-on标签:它的作用是一个bean实例化的过程需要依赖于另一个bean的初始化,也就是说被依赖的bean将会在需要依赖的bean初始化之前加载。
获取当前Bean所依赖的dependsOnBean,检查是否循环依赖了,保存依赖关系,并且先初始化dependsOnBean。
首先检查循环依赖,出现了一个缓存:dependentBeanMap(保存的是beanName,所有依赖此BeanName的Bean集合);
通过这个缓存得到(依赖beanName的Bean集合),检查集合中是否有dependentBeanName(beanName依赖的),即代表循环依赖了。

private boolean isDependent(String beanName, String dependentBeanName, Set<String> alreadySeen) {
   String canonicalName = canonicalName(beanName);
   if (alreadySeen != null && alreadySeen.contains(beanName)) {
      return false;
   }
   Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
   if (dependentBeans == null) {
      return false;
   }
   if (dependentBeans.contains(dependentBeanName)) {
      return true;
   }
   for (String transitiveDependency : dependentBeans) {
      if (alreadySeen == null) {
         alreadySeen = new HashSet<String>();
      }
      alreadySeen.add(beanName);
      if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
         return true;
      }
   }
   return false;
}

检查完,没有循环依赖之后,再注册依赖关系到上述的dependentBeanMap缓存中;
另外,又出现了与之相对应的缓存:dependenciesForBeanMap(beanName,BeanName所依赖的所有Bean集合)。

public void registerDependentBean(String beanName, String dependentBeanName) {
   // A quick check for an existing entry upfront, avoiding synchronization...
   String canonicalName = canonicalName(beanName);
   Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
   if (dependentBeans != null && dependentBeans.contains(dependentBeanName)) {
      return;
   }

   // No entry yet -> fully synchronized manipulation of the dependentBeans Set
   synchronized (this.dependentBeanMap) {
      dependentBeans = this.dependentBeanMap.get(canonicalName);
      if (dependentBeans == null) {
         dependentBeans = new LinkedHashSet<String>(8);
         this.dependentBeanMap.put(canonicalName, dependentBeans);
      }
      dependentBeans.add(dependentBeanName);
   }
   synchronized (this.dependenciesForBeanMap) {
      Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
      if (dependenciesForBean == null) {
         dependenciesForBean = new LinkedHashSet<String>(8);
         this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
      }
      dependenciesForBean.add(canonicalName);
   }
}

第6步:创建Singleton Bean

sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
						@Override
						public Object getObject() throws BeansException {
							try {
								return createBean(beanName, mbd, args);
							}
							catch (BeansException ex) {
								// Explicitly remove instance from singleton cache: It might have been put there
								// eagerly by the creation process, to allow for circular reference resolution.
								// Also remove any beans that received a temporary reference to the bean.
								destroySingleton(beanName);
								throw ex;
							}
						}
					});

首先,创建了一个singletonFactory用于创建Bean,并重写了工厂的getObject():createBean(beanName, mbd, args)。这个方法就是真正的Bean的实例创建操作,之后再详细介绍。
然后通过getSingleton(String beanName, ObjectFactory singletonFactory),得到Bean的实例。

/**
	 * Return the (raw) singleton object registered under the given name,
	 * creating and registering a new one if none registered yet.
	 * @param beanName the name of the bean
	 * @param singletonFactory the ObjectFactory to lazily create the singleton
	 * with, if necessary
	 * @return the registered singleton object
	 */
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "'beanName' must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while the 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 + "'");
				}
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<Exception>();
				}
				try {
					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;
					}
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return (singletonObject != NULL_OBJECT ? singletonObject : null);
		}
	}

在工厂中做了以下几件事:

  • 加锁,避免重复创建;
  • 先尝试从缓存中获取;
  • 在创建之前,将此BeanName存入缓存:singletonsCurrentlyInCreation,意义是标记此Bean正在创建中。
  • 调用工厂的getObject方法,也就是createBean(),这个方法是一个Bean完整的创建过程。
  • 创建之后,将此BeanName从缓存singletonsCurrentlyInCreation中移出来。
  • 最后addSingleton(beanName, singletonObject),意义是此时的Bean已经完全的被创建完毕,从二级、三级缓存中移除,放入到一级缓存中。
/**
	 * Add the given singleton object to the singleton cache of this factory.
	 * 

To be called for eager registration of singletons. * @param beanName the name of the bean * @param singletonObject the singleton object */ protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT)); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }

第7步:创建Prototype Bean

Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}

与单例模式的Bean不同的是,直接调用了CreateBean方法,而没有为此Bean创建工厂。原因当然是因为Prototype类型Bean每次都创建一个新的,不需要加锁、不需要先尝试从缓存中获取、不需要实例创建完成后放入缓存,所以直接直接createBean创建即可。

第9步:getObjectForBeanInstance判断是否为FactoryBean

/**
	 * Get the object for the given bean instance, either the bean
	 * instance itself or its created object in case of a FactoryBean.
	 * @param beanInstance the shared bean instance
	 * @param name name that may include factory dereference prefix
	 * @param beanName the canonical bean name
	 * @param mbd the merged bean definition
	 * @return the object to expose for the bean
	 */
	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}

		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the
		// caller actually wants a reference to the factory.
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd == null) {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

这个方法将目标Bean分为了三种情况:

  • 此Bean不是FactoryBean,则直接返回
  • 此Bean是FactoryBean类型,且名字以&开头,则直接返回(返回此FactoryBean的原生对象单例bean)
  • 此Bean是FactoryBean类型,且名字不是以&开头,则返回此FactoryBean的getObject()得到的bean实例。当然,不可能每一次用到这个Bean的时候都调用一次getObject()方法,spring中也有一个factoryBeanObjectCache缓存,用来记录FactoryBean类型Bean的返回对象:
/** Cache of singleton objects created by FactoryBeans: FactoryBean name --> object */
	private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<String, Object>(16);

参考:一篇非常优秀的spring源码解读
Spring IoC源码学习:总览


  1. Bean的scope作用域,类型有
    Singleton:spring中默认的scope,表示Bean只被创建一份,然后放入内存缓存,之后每一次对Bean的请求或引用都从缓存中获取。
    Prototype:每次这个bean都新创建一个实例,如将其作为属性注入到另一个Bean时,或手动getBean获取时。注意,spring对于Prototype类型的Bean是不使用缓存的。
    Request:每个request作用域内的请求只创建一个实例。
    Session:每个session作用域内的请求只创建一个实例。
    GlobalSession:在porlet的web应用程序中有意义,它被各种不同的portlet所共享。 ↩︎

你可能感兴趣的:(spring,spring,java)