Bean loading of Spring Ioc (1)

foreword

In the previous article, we analyzed the initialization process of Spring's Ioc, which is actually to register beanNameand BeanDefinitionregister in DefaultListableBeanFactorythe map.
After the bean registration is completed, refresh()many post-processor methods are also called. One of the methods finishBeanFactoryInitialization(), the annotation is written above Instantiateall remaining(non-lazy-init)singletons, means that the non-lazy loaded class will be instantiated in this step to complete the class loading.
And we use the context.getBean("beanName") method. If the corresponding bean is not lazy loaded, it can be used directly, while the lazy loaded bean needs the above steps to load the class. After loading to be used.

Let's analyze the bean instantiation process of Ioc:

1. getBean

The load bean phase is triggered when we explicitly or implicitly call a BeanFactory#getBean(String name)method . code show as below:

// AbstractBeanFactory.java

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

Internally calls the doGetBean(String name, final Class<T> requiredType, Object[] args, boolean typeCheckOnly)method , which accepts four method parameters:

  • name : the name of the bean to get

  • requiredType : the type of bean to get

  • args : Parameters passed when creating the bean. This parameter is only used when creating beans.

  • typeCheckOnly : Whether to type check.

二、doGetBean

//真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方
	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		//根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖
		// 如果指定的是别名,将别名转换为规范的Bean名称
<1>		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		// 从缓存中获取已被创建过的单例Bean
<2>		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 + "'");
				}
			}

			//注意:BeanFactory是管理容器中Bean的工厂
			//     FactoryBean是创建创建对象的工厂Bean,两者之间有区别

			//获取给定Bean的实例对象,该对象要么是 bean 实例本身,要么就是 FactoryBean 创建的 Bean 对象
			//(为什么要再次获取呢,因为上面获取的sharedInstance不一定是完整的)
<3>			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			// 因为 Spring 只解决单例模式下的循环依赖,在原型模式下如果存在循环依赖则会抛出异常。
<4>			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			//对IOC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否
			//能在当前的BeanFactory中获取的所需要的Bean,如果不能则委托当前容器
			//的父级容器去查找,如果还是找不到则沿着容器的继承体系向父级容器查找
			BeanFactory parentBeanFactory = getParentBeanFactory();
			//当前容器的父级容器存在,且当前容器中不存在指定名称的Bean
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				//解析指定Bean名称的原始名称
				String nameToLookup = originalBeanName(name);
				// 若为 AbstractBeanFactory 类型,委托父类处理
				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是否需要进行类型验证,一般不需要
<5>			if (!typeCheckOnly) {
				//向容器标记指定的Bean已经被创建
				markBeanAsCreated(beanName);
			}

			try {
				//从容器中获取 beanName 相应的 GenericBeanDefinition 对象,并将其转换为 RootBeanDefinition 对象
				// 主要解决Bean继承时子类合并父类公共属性问题
<6>				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// 检查给定的合并的 BeanDefinition (是否为抽象类)
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				// 处理所依赖的 bean @DependsOn()
				// 获取当前Bean所有依赖Bean的名称
<7>				String[] dependsOn = mbd.getDependsOn();
				//如果有依赖
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						//校验该依赖是否已经注册过给当前 Bean
						if (isDependent(beanName, dep)) {
							//已注册,抛出异常
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						//没有,则先注册依赖的bean
						registerDependentBean(dep, beanName);
						//递归调用getBean(),先生成依赖的bean
						getBean(dep);
					}
				}

				// Create bean instance.
				//创建单例Bean
<8>				if (mbd.isSingleton()) {
					//这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
					sharedInstance = getSingleton(beanName, () -> {
						try {
							//创建一个指定Bean实例对象,如果有父级继承,则合并子类和父类的定义
							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.
							//显式地从容器单例模式Bean缓存中清除实例对象
							destroySingleton(beanName);
							throw ex;
						}
					});
					//获取给定Bean的实例对象
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				//创建多例Bean
				else if (mbd.isPrototype()) {
					//原型模式(Prototype)是每次都会创建一个新的对象
					Object prototypeInstance = null;
					try {
						//加载前置处理,默认的功能是注册当前创建的原型对象
						beforePrototypeCreation(beanName);
						//创建指定Bean对象实例
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						//加载后置处理,默认的功能告诉IOC容器指定Bean的原型对象不再创建
						afterPrototypeCreation(beanName);
					}
					//获取给定Bean的实例对象
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				//要创建的Bean既不是Singleton也不是Prototype
				//如:request、session、application等生命周期
				else {
					String scopeName = mbd.getScope();
					final Scope scope = this.scopes.get(scopeName);
					//Bean定义资源中没有配置生命周期范围,则Bean定义不合法
					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的实例对象
						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.
		//对创建的Bean实例对象进行类型检查
<9>		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;
	}

The code is very long and requires some patience. Let's analyze this code step by step:

  • Section <1>: For specific analysis, see2.1获取原始beanName

  • Section <2>: For specific analysis, see2.2从缓存中获取单例bean

  • Section <3>: For specific analysis, see2.3获取最终的bean实例对象

  • Section <4>: For specific analysis, see2.4原型模式依赖检查

  • Section <5>: For specific analysis, see2.5标记bean为已创建或即将创建

  • Section <6>: For specific analysis, see2.6获取BeanDefinition

  • Section <7>: For specific analysis, see2.7bean依赖处理

  • Section <8>: For specific analysis, see2.8不同作用域bean的实例化

  • Section <9>: For specific analysis, see2.9类型转换

2.1. Get the original beanName

code show as below:

final String beanName = transformedBeanName(name);

Going further, the code is as follows:

protected String transformedBeanName(String name) {
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}

BeanFactoryUtils.transformedBeanName(name)The method is mainly to remove the modifier of FactoryBean

//对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
	//如果需要得到工厂本身,需要转义
	String FACTORY_BEAN_PREFIX = "&";

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

ps: If factoryBeanthe name of one is "student", use it when obtaining factoryBeanthe created bean, and use it when getBean("student")obtaining factoryBeanitself, and getBean("&student")
then go deeper. The final code is as follows:

/** Map from alias to canonical name */
	private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);


//循环处理,从aliasMap中根据aliasName获取真实beanName,直到获取到的真实beanName为null
	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;
	}

It is mainly a process of obtaining beanName in a loop. For example, if alias A points to a bean named B, it returns B; if alias A points to alias B, and alias B points to a bean named C, it returns C

2.2. Get a singleton bean from the cache

Spring only creates a singleton bean once. Subsequently, if the bean is obtained again, it is obtained directly from the singleton cache, and this process is reflected in the #getSingleton(String beanName) method. code show as below:

	/** Cache of singleton objects: bean name --> bean instance */
	//单例bean的缓存
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name --> ObjectFactory */
	//单例对象工厂缓存
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** Cache of early singleton objects: bean name --> bean instance */
	//预加载单例bean缓存
	//存放的 bean 不一定是完整的
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

//对于单例模式的Bean整个IOC容器中只创建一次,不需要重复创建
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//从单例缓存中获取单例bean
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果缓存中没有 并且 该bean正在创建
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				// earlySingletonObjects 中没有,且允许提前创建
				if (singletonObject == null && allowEarlyReference) {
					//从缓存中获取 ObjectFactory
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						//从单例工厂中获取bean
						singletonObject = singletonFactory.getObject();
						//存入early
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

This code is very simple, the flow is as follows:

  • The first step singletonObjectsis to get the Bean object from it

  • The second step, if it is not available and the Bean is being created, earlySingletonObjectsget the Bean object from

  • The third step, if you can't get it and allow it to be created in advance, singletonFactoriesget the FactoryBean from

  • The fourth step, if it is not null, by FactoryBean.getObject()getting the bean, then adding it to earlySingletonObjects, and singletonFactoriesdeleting , the two are mutually exclusive, mainly used to solve the problem of circular dependencies

  • The summary is: Take these three Maps in turn, and if you can't get them, take the next Map

2.2.1、isSingletonCurrentlyInCreation

Another important method in the above code , the isSingletonCurrentlyInCreation(beanName)code is as follows:

private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));
	
public boolean isSingletonCurrentlyInCreation(String beanName) {
		return this.singletonsCurrentlyInCreation.contains(beanName);
	}

This method is used to determine whether the current Bean is being created. Seeing that it is a Map, we can guess that there should be a place where the BeanName being created will be put into the Map when creating a Bean. We will be specific later.

2.2.2、getObjectForBeanInstance

When we getSingleton(beanName)get the bean object, we will then call getObjectForBeanInstance()the method to get the final Bean instance.

  • Why do you need to get the Bean again, you have already got it before?

  • Because the bean we get from the cache is the original bean, not necessarily the bean we want in the end

  • How to do it? Call the #getObjectForBeanInstance(...) method for processing, which is defined to get the object of a given Bean instance, which is either the bean instance itself or the Bean object created by FactoryBean.

Look at the code:

//获取给定Bean的实例对象,主要是完成FactoryBean的相关处理
	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		//容器已经得到了Bean实例对象,这个实例对象可能是一个普通的Bean,
		//也可能是一个工厂Bean,如果是一个工厂Bean,则使用它创建一个Bean实例对象,
		//如果调用本身就想获得一个容器的引用,则指定返回这个工厂Bean实例对象

		//若为工厂类引用(name 以 & 开头) 且 Bean实例也不是 FactoryBean
		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.
		
		//如果类型不是FactoryBean,直接返回
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		Object object = null;
		//若 BeanDefinition 为 null,则从缓存中加载 Bean 对象
		if (mbd == null) {
			//从Bean工厂缓存中获取给定名称的Bean实例对象
			object = getCachedObjectForFactoryBean(beanName);
		}

		// 若 object 依然为空,则可以确认,beanInstance 一定是 FactoryBean 。从而,使用 FactoryBean 获得 Bean 对象
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			// 检测是否定义 beanName
			if (mbd == null && containsBeanDefinition(beanName)) {
				//从容器中获取指定名称的Bean定义,如果继承基类,则合并基类相关属性
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			//如果从容器得到Bean定义信息,并且Bean定义信息不是虚构的,
			//则让工厂Bean生产Bean实例对象
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			//调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean方法,
			//实现工厂Bean生产Bean对象实例的过程
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

First look at the process of this method:

  • 1. Type check to determine whether it is a FactoryBean

  • 2. No processing of non-FactoryBean

  • 3. Convert the bean

  • 4. Process FactoryBean type: delegate to the getObjectFromFactoryBean method for processing.

Let's go directly to step 3 and go here, indicating that the bean must be of FactoryBeantype, and then obtain the BeanDefinition corresponding to the beanName from the Ioc container. If it is not null and not abstract, call the getObjectFromFactoryBeanmethod to obtain the bean instance.

As can be seen from this, the getObjectForBeanInstance(Object beanInstance, String name, String beanName,RootBeanDefinition mbd)method is divided into two cases:

  • The first, when the instance object is a 非 FactoryBean type, directly returns the given Bean instance object beanInstance.

  • Second, when the instance object is of FactoryBeantype, get the Bean instance object from FactoryBean ( beanInstance ).

2.2.3、getObjectFromFactoryBean

Let's look at the second case:

//Bean工厂生产Bean实例对象
	protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		//为单例模式且缓存中存在
		if (factory.isSingleton() && containsSingleton(beanName)) {
			//多线程同步,以防止数据不一致
1.1			synchronized (getSingletonMutex()) {
				//从缓存中获取指定的 factoryBean
1.2				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					// 为空,则从 FactoryBean 中获取对象
					object = doGetObjectFromFactoryBean(factory, beanName);
					// Only post-process and store if not put there already during getObject() call above
					// (e.g. because of circular reference processing triggered by custom getBean calls)
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
						object = alreadyThere;
					}
					else {
1.3						if (shouldPostProcess) {
							try {
								// 对从 FactoryBean 获取的对象进行后处理
								// 生成的对象将暴露给 bean 引用
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
						}
						//将生产的实例对象添加到Bean工厂缓存中
1.4						this.factoryBeanObjectCache.put(beanName, object);
					}
				}
				return object;
			}
		}
		// 为空,则从 FactoryBean 中获取对象
2		else {
			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;
		}
	}
  • 1. Determine whether it is a singleton and exists in the cache. If it exists, go down 1.1. If it does not exist, go to the process of 2.

  • 1.1, sync lock, lock is singletonObjects, like other singleton locks, to ensure global uniqueness

  • factoryBeanObjectCache1.2. If the Bean instance is obtained from the cache , if it cannot be obtained, the method is called to obtain it, and the method doGetObjectFromFactoryBean()is actually called at the end.factory.getObject()

  • 1.3. If post-processing is required (shouldPostProcess = true), proceed to the next processing postProcessObjectFromFactoryBean()method to post-process the Bean instance object obtained from FactoryBean. Its default implementation is to directly return the object object without any processing. code show as below:

protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
		return object;
	}

But subclasses can be overridden, e.g. to apply post-processors, etc.

  • 1.4, add to the factoryBeanObjectCache cache
  • 2. If it does not exist in the cache, also call doGetObjectFromFactoryBean()to get the bean instance

Summary: At this point , we have finished the analysis
of the doGetBean() method . In the next article, we will analyze the next steps.2.2从缓存中获取单例bean2.3获取最终的bean实例对象

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324034342&siteId=291194637