上节我们了解了spring对bean的获取,我们知道了我们从缓存中获取的bean大概有两种,一种是scope不是单例的bean,一种是单例的bean但还没有初始化完成.对于这两种类型的bean:
- 第一种是spring是通过一些检测以及依赖的处理
- 第二种是spring通过初始化对应的scope来完成
首先我们来看一下spring对于第一种的处理过程:
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//如果容器中没有找到,则从父类容器中加载
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
//当前类的爸爸中没找到,从爷爷辈去找,直到找到
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
//调用AbstractBeanFactory的doGetBean方法去获取bean的实例
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
//args为首次创建bean的实例时的参数
else if (args != null) {
//使用代理的方式去获取bean实例
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
//bean的真实类型
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
//这里表示我们的args和requiredType都为null,直接通过得到的bean的名字去获取实例
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
//对bean的真实类型检查,在检查之前不可使用该bean
if (!typeCheckOnly) {
//对已经创建完的bean的实例做标记,如:已完成创建
markBeanAsCreated(beanName);
}
try {
//合并父子bean的定义
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查合并之后的bean的定义
checkMergedBeanDefinition(mbd, beanName, args);
//先初始化当前bean所依赖的bean
//如:我的订单类需要商品类,此刻spring会先初始化商品类,大概就是这样的
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 + "'");
}
//给当前bean注册一个依赖bean
registerDependentBean(dep, beanName);
try {
//递归处理
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
//创建bean实例
//单例的情况下
if (mbd.isSingleton()) {
//从缓存(singletonObjects)中去拿
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//最后从缓存中移除对应的实例原因有:
//1.每当有bean在创建时,允许循环参考来解析对应的beanDefinition
//2.删除临时引用该bean的bean
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 {
//创建完bean的处理
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
//获取bean的作用域
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 = 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);
}
}
简单的来捋一下过程:
- 首先是判断当前bean是否在创建过程中,如果是直接抛BeanCurrentlyInCreationException异常
AbstractBeanFactory.java
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
这就是检测,跟踪代码来到:
/** Names of beans that are currently in creation. */
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<>("Prototype beans currently in creation");
/**
* Return whether the specified prototype bean is currently in creation
* (within the current thread).
* @param beanName the name of the bean
*/
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}
- 对parentBeanFactory的检测
//如果容器中没有找到,则从父类容器中加载
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
//当前类的爸爸中没找到,从爷爷辈去找,直到找到
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
//调用AbstractBeanFactory的doGetBean方法去获取bean的实例
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
//args为首次创建bean的实例时的参数
else if (args != null) {
//使用代理的方式去获取bean实例
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
//bean的真实类型
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
//这里表示我们的args和requiredType都为null,直接通过得到的bean的名字去获取实例
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
可以看到的是,当获取到的parentBeanFactory不为null且containsBeanDefinition不包含beanDefinition实例时,递归处理寻找,直到找到为止
其次在整个的过程中,我们可以看到的是将获取bean的任务交给了parentBeanFactory#getBean方法处理
- 首先是获取最原始的bean
String nameToLookup = originalBeanName(name);
/**
* Determine the original bean name, resolving locally defined aliases to canonical names.
* @param name the user-specified name
* @return the original bean name
*/
protected String originalBeanName(String name) {
String beanName = transformedBeanName(name);
if (name.startsWith(FACTORY_BEAN_PREFIX)) {
beanName = FACTORY_BEAN_PREFIX + beanName;
}
return beanName;
}
在获取的过程中,首先是对name的转换,如果name是以&开头,那么我们转换之后的beanName就应该是"&"+beanName
- 之后是通过getBean()方法来获取bean
- 类型检查
//对bean的真实类型检查,在检查之前不可使用该bean
if (!typeCheckOnly) {
//对已经创建完的bean的实例做标记,如:已完成创建
markBeanAsCreated(beanName);
}
代码很简单,我们可以看到参数typeCheckOnly是关键点,其目的是调用getBean()时,表示是否仅仅作为获取bean是的类型检查,如果不是仅仅做类型检查,而是在创建bean的过程中则调用markBeanAsCreated方法对创建过程中的bean进行标记,这里就是这么做的,我们直接看代码:
AbstractBeanFactory.java
/** 该缓存中存放的是已经创建完成的bean*/
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
/**
* 1.该方法的主要的作用就是将我们的bean做一个标记:如该bean已经创建或者是正在创建
* 2.允许bean工厂去优化自己本身的缓存,这样可以保证该bean的重复创建:原型
* @param beanName bean的名字
*/
protected void markBeanAsCreated(String beanName) {
//这里表示alreadyCreated缓存中没有创建的bean
if (!this.alreadyCreated.contains(beanName)) {
//全局的同步锁
//mergedBeanDefinitions为合并后的beanDefinition
synchronized (this.mergedBeanDefinitions) {
//alreadyCreated中没有的话
if (!this.alreadyCreated.contains(beanName)) {
// Let the bean definition get re-merged now that we're actually creating
// the bean... just in case some of its metadata changed in the meantime.
//从mergedBeanDefinitions删除beanName对应的bean,等到下一次访问时在创建它
clearMergedBeanDefinition(beanName);
//将beanName进行保存操作
this.alreadyCreated.add(beanName);
}
}
}
}
/**
* Remove the merged bean definition for the specified bean,
* recreating it on next access.
* @param beanName the bean name to clear the merged definition for
*/
protected void clearMergedBeanDefinition(String beanName) {
this.mergedBeanDefinitions.remove(beanName);
}
- 将beanDefinition合并为rootBeanDefinition
AbstractBeanFactory.java
//合并父子bean的定义
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查合并之后的bean的定义
checkMergedBeanDefinition(mbd, beanName, args);
首先是获取RootBeanDefinition的过程,跟踪代码:
AbstractBeanFactory.java
/** Map from bean name to merged RootBeanDefinition. */
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
//以最快的速度从缓存中去检索,缩小检索范围
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
return mbd;
}
//获取RootBeanDefinition
//如果返回的子beanDefinition的话,递归合并beanDefinition相关属性
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
简单的过一下获取合并后的RootBeanDefinition的步骤:
(1). 首先是从mergedBeanDefinitions缓存中通过beanName去获取RootBeanDefinition,如果存在则返回.
(2). 不存在的话,调用getMergedBeanDefinition方法获取,如果获取到的是子beanDefinition的话进行合并相关属性,这里关于如何合并的过程不再细说:
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
(3). 调用checkMergedBeanDefinition(mbd, beanName, args)进行对bean的检查
/**
* Check the given merged bean definition,
* potentially throwing validation exceptions.
* @param mbd the merged bean definition to check
* @param beanName the name of the bean
* @param args the arguments for bean creation, if any
* @throws BeanDefinitionStoreException in case of validation failure
*/
protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args)
throws BeanDefinitionStoreException {
if (mbd.isAbstract()) {
throw new BeanIsAbstractException(beanName);
}
}
- 循环依赖处理
所谓依赖,实际上是一个bean作为另一个bean的引用,我们来看代码:
//先初始化当前bean所依赖的bean
//如:我的订单类需要商品类,此刻spring会先初始化商品类,大概就是这样的
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 + "'");
}
//给当前bean注册一个依赖bean
registerDependentBean(dep, beanName);
try {
//递归处理
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
当一个bean需要依赖与另外一个bean,则先初始化需要依赖的bean,简单的看一下过程:
4.1.初始化依赖的bean
AbstractBeanDefinition.java
private String[] dependsOn;
public String[] getDependsOn() {
return this.dependsOn;
}
4.2. 循环遍历然后调用isDependent(beanName, dep)方法检验当前依赖是否注册,是的话抛BeanCreationException异常.
DefaultSingletonBeanRegistry.java
/**保存的是依赖beanName之间的映射关系*/
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
protected boolean isDependent(String beanName, String dependentBeanName) {
synchronized (this.dependentBeanMap) {
return isDependent(beanName, dependentBeanName, null);
}
}
private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
//如果是alreadySeen中包含beanName说明已经注册了依赖的bean
if (alreadySeen != null && alreadySeen.contains(beanName)) {
return false;
}
//获取最原始bean 的beanName
String canonicalName = canonicalName(beanName);
//从dependentBeanMap中通过beanName获取所有的依赖bean的集合
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
return false;
}
//如果dependentBeanName存在于dependentBeans中,说明已经有依赖的bean
if (dependentBeans.contains(dependentBeanName)) {
return true;
}
//遍历
for (String transitiveDependency : dependentBeans) {
if (alreadySeen == null) {
alreadySeen = new HashSet<>();
}
//将beanName添加到alreadySeen中作为参数
alreadySeen.add(beanName);
//递归调用自己
if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
return true;
}
}
return false;
}
4.3. 调用registerDependentBean(dep, beanName)方法给当前bean注册依赖,这里是已经检验成功的情况下:
/**保存的是依赖beanName之间的映射关系*/
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
/**
* 给当前bean注册一个依赖的bean
* @param beanName 当前要创建的bean
* @param dependentBeanName 当前bean所依赖的bean的名字
*/
public void registerDependentBean(String beanName, String dependentBeanName) {
//获取原始beanName
String canonicalName = canonicalName(beanName);
// 添加 <canonicalName, <dependentBeanName>> 到 dependentBeanMap 中
synchronized (this.dependentBeanMap) {
Set<String> dependentBeans =
this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
if (!dependentBeans.add(dependentBeanName)) {
return;
}
}
//同上
synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean =
this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
dependenciesForBean.add(canonicalName);
}
}
4.4. 调用getBean(String beanName)进行依赖bean的实例化过程.
关于parentBeanFactory的检测和依赖处理到这里就说完了
网友评论