spring容器核心原理--bean的存储以及Bean的三级缓存

spring容器核心原理--bean的存储以及Bean的三级缓存,第1张

spring容器核心原理--bean的存储以及Bean的三级缓存 一.bean的存储

通常我们说,spring容器帮我们管理bean,但是什么是bean?
举个简单的例子,如果我们自己提供一个X.class类,那此时的X.class我们称之为class对象,在经过spring的一系列生命周期的处理之后,就会变成可以放到spring容器中的bean对象,我们称此时的对象是bean对象,所以,总结来说,经过一系列生命周期方法处理之后的class对象,就是bean对象;
只有经过一系列后置处理器方法的处理,才是一个合格的bean对象。

bean对象最终存储在spring容器中,我们简单的、狭义上的spring容器,在spring源码底层就是一个map集合,这个map集合存储的key是当前bean的name,如果不指定,默认的是class类型首字母小写作为key,value是bean对象。存储bean的map在DefaultListableBeanFactory类中:

private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);

当Spring容器扫描到Bean类时 , 会把这个类的描述信息, 以包名加类名的方式存到beanDefinitionMap 中,
Map , 其中 String是Key , 默认是类名首字母小写 , BeanDefinition , 存的是类的定义(描述信息) , 我们通常叫BeanDefinition接口为 : bean的定义对象。

问题思考

spring为什么不在扫描到class文件之后,立即执行生命周期方法进行初始化、实例化?而是要先放到beanDefinitionMap集合中?
因为spring所提供的容器管理功能中,某些class类并不一定是立马需要初始化的,比如:原型bean,就是在使用的时候,再去初始化。

那我们想下,如果是原型bean,并且假设我们没有beanDefinition这一层,那问题就大了,对于原型的bean,我每初始化一次,就需要去扫描一次,这样就很浪费时间了,此时,beanDefinition的作用,就显而易见了。提一嘴,spring容器在启动的过程中,对bean进行初始化实例化的时候,大致是分为了两步,第一是将class文件转换为beanDefinition对象,第二步是根据beanDefinition对象,按照配置的要求,去进行初始化、实例化
有了beanDefinition之后,beanDefinitionMap相当于一个中转站,所有要初始化的bean,都是以beanDefinitionMap中的beanDefinition的属性信息为准。

1.spring在将class文件转换为beanDefinition的时候,是没有额外的要求的,不管这个bean是单例的,还是原型的,还是懒加载的,都会扫描出来,统一放到beanDefinitionMap集合中。
2.在第二步去初始化bean的时候,才会判断当前bean是否是原型的、是否是懒加载的、是否是有依赖关系的,等

所以,我们也可以认为beanDefinition是一个中转站,这个中转站中,存放了所有的class对应的信息,如果是初始化,就根据beanDefinition的属性信息去初始化,所以,spring也提供了一系列的扩展点让我们去修改beanDefinition、增加、删除beanDefinition。
所以,简单来说,我们自己写得一个class文件,在放到spring容器中,是这样的一个步骤:

A.class --> beanDefinition --> bean

所以,中间加了一层beanDefinition之后,那很有可能就会出现,我们提供的是X.class,但是在将class存入到beanDefinition之后,将对应的beanDefinition属性的beanClass设置为了Y.class,那这时候初始化的就是Y对象,而不是X对象。
这只是举个例子,想要说明的是:我们提供了一个X.class,正常情况下,初始化的就是x这个bean,但是在特殊情况下,我们可以将X的beanDefinition的beanClass修改为Y.class,这样就偷天换日了,实际初始化的是Y对象;这个过程就依赖于Spring所提供的N多个扩展点。
在将class放入到beanDefinitionMap之后,可以通过扩展点去修改beanDefinition的属性信息。

所以,我们提供的X类,最后并不一定初始化的就是X这个bean,许多底层框架,也是通过beanDefinition的扩展点去完成自己的业务逻辑的。

如果我们想在Spring对class初始化的过程中,进行干预怎么办?
Spring提供了一系列的扩展点,让我们根据自己的业务需求,去处理class文件从class变成bean对象过程中的关键点。我觉得,这也是Spring强大的地方,不仅仅帮我们去管理bean,也提供了相应的扩展点,让我们根据自己的需求去扩展Spring,比如:beanFactoryPostProcessor可以让我们去干预beanDefinitionMap中的beanDefinition对象;spring的后置处理器,可以让我们根据自己的需求,去干预各个后置处理器方法执行的逻辑。

二.Bean的三级缓存

在DefaultSingletonBeanRegistry类中为Bean的创建设置了三级缓存:

第一级缓存:singletonObjects
第二级缓存:earlySingletonObjects
第三级缓存:singletonFactory

private final Map singletonObjects = new ConcurrentHashMap<>(256);


private final Map> singletonFactories = new HashMap<>(16);


private final Map earlySingletonObjects = new ConcurrentHashMap<>(16);
完成一个Bean对象的创建需要三步

1.创建Bean实例(createBeanInstance)
-这里主要 *** 作是从之前已经处理好的BeanDefition(Bean定义信息)中实例化一个对象。

2.Bean对象属性赋值(populateBean)
-像@Autowired注解修饰的成员变量是在这一步完成注入的。

3.Bean对象的初始化(初始化Bean实例)
-这一步会去调用这个Bean继承了某些接口(BeanNameAware等)的方法。

在AbstractAutowireCapableBeanFactory类中创建Bean实例:

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

	// Instantiate the bean.
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	Object bean = instanceWrapper.getWrappedInstance();
	Class beanType = instanceWrapper.getWrappedClass();
	if (beanType != NullBean.class) {
		mbd.resolvedTargetType = beanType;
	}

	// Allow post-processors to modify the merged bean definition.
	synchronized (mbd.postProcessingLock) {
		if (!mbd.postProcessed) {
			try {
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Post-processing of merged bean definition failed", ex);
			}
			mbd.postProcessed = true;
		}
	}

	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		if (logger.isTraceEnabled()) {
			logger.trace("Eagerly caching bean '" + beanName +
					"' to allow for resolving potential circular references");
		}
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
		populateBean(beanName, mbd, instanceWrapper);
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	catch (Throwable ex) {
		if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
			throw (BeanCreationException) ex;
		}
		else {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
		}
	}

	if (earlySingletonExposure) {
		Object earlySingletonReference = getSingleton(beanName, false);
		if (earlySingletonReference != null) {
			if (exposedObject == bean) {
				exposedObject = earlySingletonReference;
			}
			else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
				String[] dependentBeans = getDependentBeans(beanName);
				Set actualDependentBeans = new linkedHashSet<>(dependentBeans.length);
				for (String dependentBean : dependentBeans) {
					if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
						actualDependentBeans.add(dependentBean);
					}
				}
				if (!actualDependentBeans.isEmpty()) {
					throw new BeanCurrentlyInCreationException(beanName,
							"Bean with name '" + beanName + "' has been injected into other beans [" +
							StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
							"] in its raw version as part of a circular reference, but has eventually been " +
							"wrapped. This means that said other beans do not use the final version of the " +
							"bean. This is often the result of over-eager type matching - consider using " +
							"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
				}
			}
		}
	}

	// Register bean as disposable.
	try {
		registerDisposableBeanIfNecessary(beanName, bean, mbd);
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
	}

	return exposedObject;
}
三级缓存的应用时机

Bean对象在被实例化后会放入第三级缓存(addSingletonFactory)

if (earlySingletonExposure) {
	if (logger.isTraceEnabled()) {
		logger.trace("Eagerly caching bean '" + beanName +
				"' to allow for resolving potential circular references");
	}
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
二级缓存的应用时机

在Bean对象被放入三级缓存后,以后的 *** 作如果要进入缓存查询,就会将
三级缓存中的Bean对象移动到二级缓存**,此时放在三级缓存的Bean对象会被移除

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// Quick check for existing instance without full singleton lock
	Object singletonObject = this.singletonObjects.get(beanName);
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		singletonObject = this.earlySingletonObjects.get(beanName);
		if (singletonObject == null && allowEarlyReference) {
			synchronized (this.singletonObjects) {
				// Consistent creation of early reference within full singleton lock
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					singletonObject = this.earlySingletonObjects.get(beanName);
					if (singletonObject == null) {
						ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
						if (singletonFactory != null) {
							singletonObject = singletonFactory.getObject();
							this.earlySingletonObjects.put(beanName, singletonObject);
							this.singletonFactories.remove(beanName);
						}
					}
				}
			}
		}
	}
	return singletonObject;
}
一级缓存的应用时机

在Bean对象创建完毕后会放入一级缓存。(addSingleton)
在要用到一个Bean对象之前,都会尝试从缓存中获取,最先就是判断一级缓存中存不存在,所以称“一级”。

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
	Assert.notNull(beanName, "Bean name must not be null");
	synchronized (this.singletonObjects) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			if (this.singletonsCurrentlyInDestruction) {
				throw new BeanCreationNotAllowedException(beanName,
						"Singleton bean creation not allowed while singletons of this factory are in destruction " +
						"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
			}
			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) {
				// Has the singleton object implicitly appeared in the meantime ->
				// if yes, proceed with it since the exception indicates that state.
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					throw ex;
				}
			}
			catch (BeanCreationException ex) {
				if (recordSuppressedExceptions) {
					for (Exception suppressedException : this.suppressedExceptions) {
						ex.addRelatedCause(suppressedException);
					}
				}
				throw ex;
			}
			finally {
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = null;
				}
				afterSingletonCreation(beanName);
			}
			if (newSingleton) {
				addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject;
	}
}

三级缓存其实就是三个Map,它们在特定的时间、特定的场合被使用,以解决特定的问题。
(其实整个Spring容器就是许多的Map组成,保存了环境信息、Bean定义信息、Bean实例等等)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5159834.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-18
下一篇 2022-11-18

发表评论

登录后才能评论

评论列表(0条)

保存