当前位置 : 主页 > 编程语言 > 其它开发 >

Spring Ioc源码分析系列--Bean实例化过程(一)

来源:互联网 收集:自由互联 发布时间:2022-05-28
Spring Ioc源码分析系列--Bean实例化过程(一)前言 上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对IoC容器启动方法也就是 refresh() 方法
Spring Ioc源码分析系列--Bean实例化过程(一) 前言

上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对IoC容器启动方法也就是refresh()方法的简单分析。但是之前的分析在对容器实例化Bean的过程的略过了,留到了这后续的文章分析,所以这篇文章会对Bean的实例化过程做一个介绍。

首先来理一下本文的思路:关键词是实例化。由于Spring是利用反射实现的实例化,脑子里先简单想一下Java里利用发射实例化一个对象需要哪些步骤和操作。毫无疑问,我们首先要知道对象的class,接着需要确定使用什么构造函数以及确定构造函数的参数等。利用这些已经基本可以实现一个对象的实例化,当然实际上需要的东西可能更多更复杂,这里只是举个例子。那么需要的这些信息可以去哪里提取呢?对Spring有了解的可能都马上能想到BeanDefinition,这是一份原料表,里面有我们构造一个实例化对象所需的所有参数。如果不太理解这个定义,可以参考一下上篇文章的例子。

如果不清楚BeanDefinition是从哪里来的以及不清楚如何定义的,可以参考之前的文章Spring Ioc源码分析系列--Ioc源码入口分析的关键实现系列方法 loadBeanDefinitions ()。这篇文章讲解注册的时候只是说了注册到容器里,并没有说明具体是注册到了哪里,这里点明一下,所谓讲BeanDefinition注册到容器里,就是将BeanDefinition放入到容器的一个Map里,具体是注册到了DefaultListableBeanFactorybeanDefinitionMap属性里,beanName会保存到beanDefinitionNames属性里,这是个list集合,里面的beanName会保持注册时候的顺序。

实例化的开始就是从遍历所有的beanName开始,话不多说,开始分析吧。

源码分析 bean实例化入口

还记得实例化入口的方法名吗?回忆一下,算了,反正也不会有人记得。是beanFactory.preInstantiateSingletons(),具体实现是在DefaultListableBeanFactory类里。

跟进代码查看,可以看到,这段代码分为两部分,第一个for循环用于先实例化对象,第二个for循环完成一些实例化之后的回调操作。我们先来看第一个for循环,首先是遍历所有的beanNames获取BeanDefinition,然后根据工厂bean非工厂bean进行相应处理,最后调用getBean(beanName)实例化对象。注意这里实例化的是非抽象的、单例的并且是非懒加载的bean,这个前提非常重要。

	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		// 所有bd的名称
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		// 遍历所有bd,一个个进行创建
		for (String beanName : beanNames) {
			// 获取到指定名称对应的bd
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 对不是延迟加载的单例的Bean进行创建
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				// 判断是否是一个FactoryBean
				if (isFactoryBean(beanName)) {
					// 如果是一个factoryBean的话,先创建这个factoryBean,创建factoryBean时,需要在beanName前面拼接一个&符号
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							// 判断是否是一个SmartFactoryBean,并且不是懒加载的,就意味着,在创建了这个factoryBean之后要立马调用它的getObject方法创建另外一个Bean
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					// 不是factoryBean的话,我们直接创建就行了
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		// 在创建了所有的Bean之后,遍历为所有适用的 bean 触发初始化后回调,也就是这里会对延迟初始化的bean进行加载...
		for (String beanName : beanNames) {
			// 这一步其实是从缓存中获取对应的创建的Bean,这里获取到的必定是单例的
			Object singletonInstance = getSingleton(beanName);
			// 判断是否是一个SmartInitializingSingleton,
			// 最典型的就是我们之前分析过的EventListenerMethodProcessor,
			// 在这一步完成了对已经创建好的Bean的解析,会判断其方法上是否有 @EventListener注解,
			// 会将这个注解标注的方法通过EventListenerFactory转换成一个事件监听器并添加到监听器的集合中
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}
获取BeanDefinition

首先跟进getMergedLocalBeanDefinition(beanName)方法,这里首先会尝试从mergedBeanDefinitions里去获取,这个mergedBeanDefinitions存放着已经合并过的BeanDefinition,获取不到再真正调用getMergedBeanDefinition(beanName, getBeanDefinition(beanName))去获取。

	/**
	 * Return a merged RootBeanDefinition, traversing the parent bean definition
	 * if the specified bean corresponds to a child bean definition.
	 *
	 * 返回一个合并的 RootBeanDefinition,如果指定的 bean 对应于子 bean 定义,则遍历父 bean 定义。
	 *
	 * @param beanName the name of the bean to retrieve the merged definition for
	 * @return a (potentially merged) RootBeanDefinition for the given bean
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @throws BeanDefinitionStoreException in case of an invalid bean definition
	 */
	protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
		// Quick check on the concurrent map first, with minimal locking.
		// 首先检查 mergedBeanDefinitions ,最小程度影响并发性能
		RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
		if (mbd != null && !mbd.stale) {
			return mbd;
		}
		return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
	}

先看getBeanDefinition(beanName),这个方法就是简单的去beanDefinitionMap里获取BeanDefinition,如果获取不到,就抛出异常。beanDefinitionMap就是上面说到的BeanDefinition存放的地方。

	public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
		BeanDefinition bd = this.beanDefinitionMap.get(beanName);
		if (bd == null) {
			if (logger.isTraceEnabled()) {
				logger.trace("No bean named '" + beanName + "' found in " + this);
			}
			throw new NoSuchBeanDefinitionException(beanName);
		}
		return bd;
	}

接下来就进入到getMergedBeanDefinition()方法获取BeanDefinition,为啥要从beanDefinitionMap获取了还进行一个merged获取呢?这是因为Bean有层次关系,子类需要合并父类的属性方法等,所以要进行一次合并,合并完成后会放入到mergedBeanDefinitions里,功能和属性名区分度还是十分贴切的

网友评论