Bean loading of Spring Ioc (2)

In the last article, Spring Ioc Bean Loading (1) , we analyzed the two steps of the Bean loading doGetBean() method in Spring Ioc, 2.2从缓存中获取单例beanand 2.3获取最终的bean实例对象then we analyzed the remaining steps.
Go directly to the code:

//真正实现向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原型模式依赖检查(Prototype)和从 parentBeanFactory 获取 Bean

  • 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.4. Prototype mode dependency check (Prototype) and get Bean from parentBeanFactory

Prototype mode dependency check, the corresponding code is as follows:

if (isPrototypeCurrentlyInCreation(beanName)) {
	throw new BeanCurrentlyInCreationException(beanName);
	}

Follow in:

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

protected boolean isPrototypeCurrentlyInCreation(String beanName) {
		//从ThreadLocal中取出正在创建的prototype
		Object curVal = this.prototypesCurrentlyInCreation.get();
		return (curVal != null &&
				(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
	}

Spring only handles circular dependencies in singleton mode, and throws exceptions directly for circular dependencies in prototype mode.
Spring will store the prototype modeThreadLoacl bean that is being created , where ThreadLoacl is used to determine whether the current bean has been created.

Get Bean from parentBeanFactory , the corresponding code is as follows:

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

If there is no corresponding BeanDefinition object in the current container cache, it will try to load it from the parent class factory (parentBeanFactory), and then recursively call the getBean(...) method

2.5. Mark the bean as created or about to be created

The corresponding code is as follows:

//创建的Bean是否需要进行类型验证,一般不需要
			if (!typeCheckOnly) {
				//向容器标记指定的Bean已经被创建
				markBeanAsCreated(beanName);
			}

typeCheckOnlyIs a parameter in the doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) method, generally this parameter is passed false

Then follow the markBeanAsCreated()method:

protected void markBeanAsCreated(String beanName) {
		// 没有创建
		if (!this.alreadyCreated.contains(beanName)) {
			synchronized (this.mergedBeanDefinitions) {
				// 再次检查一次:DCL 双重校验
				if (!this.alreadyCreated.contains(beanName)) {
					clearMergedBeanDefinition(beanName);
					// 添加到已创建 bean 集合中
					this.alreadyCreated.add(beanName);
				}
			}
		}
	}

The familiar double check in the singleton pattern is used here.

2.6, get BeanDefinition

The corresponding code is as follows:

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

This code comment is very detailed, so I won't explain much.

2.7, bean dependency processing

The corresponding code is as follows:

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

There is an @DependsOnannotation in spring, which is used for dependency loading. For example, the A object cannot be loaded until the B object is loaded, then an @DependsOn(value = "B")annotation can be added on A to meet our requirements.
In fact @DependsOn, the principle of implementation is the above code.

  • BeanDefinition<1>. By calling the method we got from the IoC container earlier, we can get mbd.getDependsOn()all the dependencies of the current bean.

  • <2> Traverse these dependencies to determine whether this dependency has been registered with the current Bean

  • <3>, no, first register the dependent bean

  • <4>, recursively call getBean(), first generate dependent beans

<2> Traverse these dependencies to determine whether this dependency has been registered with the current Bean

Code:

	
	// 保存的是bean与其依赖的映射关系:B - > A
	private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

        //保存的是bean与其依赖的映射关系:A - > B
	private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
		if (alreadySeen != null && alreadySeen.contains(beanName)) {
			return false;
		}
		// 获取当前原始 beanName
		String canonicalName = canonicalName(beanName);
		// 获取该bean依赖的其他bean集合
		Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
		if (dependentBeans == null) {
			return false;
		}
		// 存在,则证明该依赖已经注册到bean中
		if (dependentBeans.contains(dependentBeanName)) {
			return true;
		}
		// 递归检测依赖
		for (String transitiveDependency : dependentBeans) {
			if (alreadySeen == null) {
				alreadySeen = new HashSet<>();
			}
			alreadySeen.add(beanName);
			if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
				return true;
			}
		}
		return false;
	}

This code is very simple, mainly by dependentBeanMapobtaining all the dependencies corresponding to the current bean dependentBeans, then judging whether it has been registered, and then recursively checking whether the dependent bean has dependencies, and if so, recursively calling isDependent()the check

<3>, no, first register the dependent bean

If no dependent bean is registered to the bean, perform the registration registerDependentBean(dep, beanName):

	// 保存的是bean与其依赖的映射关系:B - > A
	private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

        //保存的是bean与其依赖的映射关系:A - > B
	private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

//为指定的Bean注入依赖的Bean
	public void registerDependentBean(String beanName, String dependentBeanName) {
	// A quick check for an existing entry upfront, avoiding synchronization...
	//获取原始beanName
	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
	//先从容器中:bean名称-->全部依赖Bean名称集合找查找给定名称Bean的依赖Bean
	synchronized (this.dependentBeanMap) {
		//获取给定名称Bean的所有依赖Bean名称
		dependentBeans = this.dependentBeanMap.get(canonicalName);
		if (dependentBeans == null) {
			//为Bean设置依赖Bean信息
			dependentBeans = new LinkedHashSet<>(8);
			this.dependentBeanMap.put(canonicalName, dependentBeans);
		}
		//把映射关系存入集合
		dependentBeans.add(dependentBeanName);
	}
	//从容器中:bean名称-->指定名称Bean的依赖Bean集合找查找给定名称Bean的依赖Bean
	synchronized (this.dependenciesForBeanMap) {
		Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
		if (dependenciesForBean == null) {
			dependenciesForBean = new LinkedHashSet<>(8);
			this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
		}
		//把映射关系存入集合
		dependenciesForBean.add(canonicalName);
	}
	}

Applying the above example, if A @DependsOn(value = "B") , that is to say, A depends on B, then in this method registerDependentBean(dep, beanName), the parameter dep is B, and the beanName is A.
In this code, the dependencies between beans are actually registered in two maps.

  • dependentBeanMap is stored in (B,A)

  • dependenciesForBeanMap is stored in (A,B)

<4>, recursively call getBean(dep), first generate dependent beans

At this point, recursively call the getBean(beanName) method, that is, doGetBean(beanName) to re-run the current process to instantiate the dependent beans first. After the dependent bean is instantiated, the current bean will continue to execute.

2.8. Instantiation of beans with different scopes

Code:

        // Create bean instance.
	//创建单例Bean
	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);
		}
	}

This code is clearly divided into 3 parts:

  • singleton bean instantiation

  • Prototype Bean instantiation

  • Other types of Bean instantiation (session, request, etc.)

Let's first look at the singleton Bean instantiation:

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

The scope of a Spring Bean defaults to singleton. There are other scopes like prototype, request, session, etc.
Different scopes have different initialization strategies.
See Spring Ioc Bean Loading (3): Bean Creation of Each Scope .

2.9, type conversion

Code:

// Check if required type matches the type of the actual bean instance.
	//对创建的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;

requiredTypeIt is a parameter that can be passed in by the getBean() method, that is, the bean can be obtained according to the specified beanName and requiredType.

But in general, type checking is not required, and it requiredTypeis usually null, such asgetBean(beanName)

requiredTypeFollow this logic when it is not null.

总结:

At this point, we have roughly analyzed the spring loaded bean, that is, getBean() , and we will write a few more articles to introduce some of these steps in detail.

Reference:
Taro source code

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

Guess you like

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