Spring之bean实例的创建

在上一篇博客中,我们已经对bean的加载跟着源代码完整的走了一遍,代码读起来很轻松,主要还是Spring的编程风格,它把每段代码分割成一个一个的小逻辑,使得每个逻辑处理起来都不是很负责,非常有利于我们学习。接下来,我们继续对bean实例的创建进行阅读。
Spring启动之后,如果我们不主动从里面获取bean的实例,Spring是不会主动创建实例的,所以实例的创建流程是从下面这段代码开始的

Person person = (Person) beanFactory.getBean("person");

虽然只有简单的一句,但是他后面的逻辑确是很复杂的,我们开始。


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

同样符合我们发现的规律,干活的永远都是do开头的方法,这就类似于被戴了帽子吧!

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		//首先将用户传入的名字变成在IOC存储的beanName
		final String beanName = transformedBeanName(name);
		Object bean;

		// 先按照用户要到的bean是单例来查找
		Object sharedInstance = getSingleton(beanName);
		//如果能从IOC容器的缓存中查到,那么这个bean一定是单例并且已经被加载过了
		if (sharedInstance != null && args == null) {
			...
			//由于用户获得的bean可能是继承了FactroyBean的bean,所以还要进行一些验证和处理
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// 我们假设在循环引用当中
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
			...
			try {
				//获得一个合并的beanDefinition,其实就是复制了一个beanDefinition并且对其中缺少的属性进行填充
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				//确保初始化当前bean所依赖的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);
					}
				}

				// 创建单例
				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);
				}
				//创建一个单例
				else if (mbd.isPrototype()) {
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
							//由于用户获得的bean可能是继承了FactroyBean的bean,所以还要进行一些验证和处理
					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可能是继承了FactroyBean的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.
		...
		return (T) bean;
	}

这个方法先假设要获取的bean是一个单例,如果从IOC容器中得到了实例,说明他是一个单例,调用getObjectForBeanInstance直接返回,如果没有获得到,创建一个MergedBeanDefinition根据他所定义的是单例还是多例进行bean的实例,在这个方法中还牵扯到了循环引用的问题,在这篇博客中我们就不细讲了,之后要单独写一篇博客介绍它,接下来我们先看一下怎么从IOC容器中获得单例:

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//从IOC容器的缓存中查找
		Object singletonObject = this.singletonObjects.get(beanName);
		//判断对应的单例对象是否在创建中,当单例对象没有被初始化完全(例如A定义的构造函数依赖了B对象,得先去创建B对象,或者在populatebean过程中依赖了B对象,得先去创建B对象,此时A处于创建中)
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			//在多线程环境中,对一级缓存上锁
			synchronized (this.singletonObjects) {
				//从二级缓存中获取对象
				singletonObject = this.earlySingletonObjects.get(beanName);
				//如果没有获得到,可能要获得的bean在三级缓存中
				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;
	}

这个方法中先是从一级缓存中获取实例,获取不到,再从二级缓存中获取,最后再从三级缓存中获取,Spring中设置三级缓存主要是为了解决单例的循环引用,在这里就不细讲了。
获取到了实例最终都要执行这个方法,那么我们就先来看看他是做什么的

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
		...
		// 如果instance不是FactoryBean实例,或者想要获取的就是FactoryBean实例,那么直接返回就好
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd == null) {
			//获取缓存的,通过FactoryBean暴露出来的对象
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// 需要从FactoryBean中获取实例
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			//如果对象是单例对象,则缓存从FactoryBean获得的对象。
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

如果我们创建的是一个FactoryBean,而用户想要bean实例,我们来看Spring是怎么处理的

protected Object getCachedObjectForFactoryBean(String beanName) {
		return this.factoryBeanObjectCache.get(beanName);
	}

会先尝试从缓存中获取,这个缓存中专门缓存了有FactoryBean创建的对象,找到后就直接返回了,没有还要继续处理:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		//如果这个factoryBean是单例的,并且已经有了他的缓存
		if (factory.isSingleton() && containsSingleton(beanName)) {
			synchronized (getSingletonMutex()) {
				//从缓存中直接获取factoryBean创建的对象
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					//没有获取到,说明缓存中没有,从factory中直接getObject
					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 {
						if (shouldPostProcess) {
							try {
								//这个方法是交给用户用来定制处理的
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
						}	
						//将获取的对象放到缓存中
						this.factoryBeanObjectCache.put(beanName, object);
					}
				}
				return object;
			}
		}
		else {
			//factoryBean是多例的,每次都要获取
			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;
		}
	}

Spring再次尝试从缓存中获取,获取不到说明缓存中真的没有了,那么就要从factoryBean中获取,获取完之后需要将这个对象放到缓存中,好了,到这用户就得到了他想要的bean实例了。接着我们看一下这个实例到底是怎么创建出来的,我们只看单例是怎么创建的,多例无非就是每次创建完后都不缓存。

if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							...
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

这里是创建单例的入口,从这个地方开始分析,我们会发现这段代码里有个回调函数,里卖弄有一个createBean方法,看来他是创建bean实例的核心了,那我们就先来看他:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		...
		RootBeanDefinition mbdToUse = mbd;

		// 获得我们要实例的bean的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) {
		...
		}

		try {
			// 让beanpostprocessor有机会返回一个代理而不是目标bean实例。
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			...
		}

		try {
			//创建一个实例
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isDebugEnabled()) {
				logger.debug("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException ex) {
			...
		}
	}

同样,干活的还是那种戴帽子的方法doCreateBean,但是由于里面牵扯到了循环引用的问题,下一篇文章在讲,我们只需要知道在这个方法中,实例化了bean,并且进行了属性的填充。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		//锁住缓存
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				...
				//创建对象之间先做一些检查
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					//执行回调函数,获得创建的实例
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					...
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					将创建的实例放到缓存中
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

在这个方法中得到了创建的单例实例并且把它放到了缓存中。执行到这,最简单的实例化一个bean已经完成了,剩下的就是检查时候使用户所需要的类型。我们看一下实例化的流程:
一、指定要获取的实例的id
二、首先将用户传入的名字变成在IOC存储的beanName
三、先在缓存中查找,如果找到了说明是单例,接着进行根据用户的要求获取factoryBean或者是普通bean返回就好了,缓存中没有
四、缓存中没有,要根据用户要实例的bean是单例还是多例通过反射进行实例化,如果是单例需要添加到缓存中
这次的流程不是很复杂,但是其中牵扯到了循环引用的问题,在下一篇中,我们来单独介绍。

猜你喜欢

转载自blog.csdn.net/m0_37343985/article/details/82822376