Spring5 源码阅读笔记(1.4.4)多例的实例化

在此之前的文章都讲的是单例的实例化。本节讲的是多例的实例化。

什么是多例?
多例就是每次 getBean 操作得到的不是同一个对象。

我们在一个类上打上 @Component 注解后,还可以再打上一个 @Scope(“prototype”),使这个类在实例化的时候是多例的。

Scope 即作用域,除了单例和多例以外,还有其它的模式。它们最大的区别是,如何管理实例对象。单例是在完成工厂初始化的时候就将所有的 Bean 实例放进了缓存,使我们拿到的都是相同的实例,省去了反复创建和销毁的麻烦。而多例在工厂初始化的时候并没有创建,也没有放实例的缓存,所以我们每次拿到的是不同的对象。

以下是 doGetBean 方法中的一段:

else if (mbd.isPrototype()) {
			// It's a prototype -> create a new instance.
			Object prototypeInstance = null;
			try {
				//1.4.4.1
				beforePrototypeCreation(beanName);
				//这个方法和单例的是一样的,见1.4.2
				prototypeInstance = createBean(beanName, mbd, args);
			}
			finally {
				//1.4.4.2
				afterPrototypeCreation(beanName);
			}
			//该方法是FactoryBean接口的调用入口
			bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
		}

完整的代码见Spring5 源码阅读笔记(1.4)finishBeanFactoryInitialization(beanFactory) 完成Bean工厂初始化

在这那一节中,我们知道如果是非抽象的且是单例的且非懒加载的 Bean,Spring 会在完成Bean工厂初始化这个方法里,将它初始化。但多例的并不会。所以在后来的 doGetBean 方法里我们才看到跟多例有关的代码。

这说明了只有当我们手动 getBean 才会进行多例的实例化。可以理解为多例是“懒加载”的。

跟源码

1.4.4.1 beforePrototypeCreation

类 AbstractBeanFactory

protected void beforePrototypeCreation(String beanName) {
	//先从表示正在创建的容器里拿,这里的容器是一个ThreadLocal
	Object curVal = this.prototypesCurrentlyInCreation.get();
	if (curVal == null) {
		//如果容器里原本没有,直接放入
		this.prototypesCurrentlyInCreation.set(beanName);
	}
	//如果容器里已经有一个beanName了,由于ThreadLocal只能存放一个值,
	//就把原来的和要新添加的打包成一个set放入容器
	else if (curVal instanceof String) {
		Set<String> beanNameSet = new HashSet<>(2);
		beanNameSet.add((String) curVal);
		beanNameSet.add(beanName);
		this.prototypesCurrentlyInCreation.set(beanNameSet);
	}
	else {
		//如果容器里本来就是一个set,就把变量放入set
		Set<String> beanNameSet = (Set<String>) curVal;
		beanNameSet.add(beanName);
	}
}

跟 prototypesCurrentlyInCreation:

在这里插入图片描述
使用 ThreadLocal 可以让多个线程彼此创建实例不受干扰。

1.4.4.2 afterPrototypeCreation

类 AbstractBeanFactory

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();
		}
	}
}
发布了144 篇原创文章 · 获赞 250 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44367006/article/details/104483799