IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring源码分析五: Bean加载之doGetBean② -> 正文阅读

[Java知识库]Spring源码分析五: Bean加载之doGetBean②

(一)序言

spring源码分析加载bean总览中对加载bean进行了总体分析,主要是对非延迟加载bean流程的关键点分析,本文将对每个关键点进行详细分析,体现在AbstractBeanFactory->doGetBean方法中的主要关键点进行代码分析,笔者如有分析错误,还请及时指出。

(二)非延迟bean加载——doGetBean

1、规范化beanName:transformedBeanName

String beanName = transformedBeanName(name);

transformedBeanName方法负责将普通bean的别名或去除工厂bean的前缀转化为beanName。

(1)BeanFactoryUtils.transformedBeanName方法是去除FactoryBean类型的bean的前缀“&”,里面有do…while循环保证beanName前缀无“&”;
(2)canonicalName方法是将bean中配置的别名转化为实际的beanName,也是采用do…while循环进行获取。

transformedBeanName代码如下:

  protected String transformedBeanName(String name) {
        //上述(1)、(2)点具体代码执行点
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}

BeanFactoryUtils工具类进行封装去除“&”,具体代码如下:

 public static String transformedBeanName(String name) {
	if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {//检查是否是"&"开头的beanName
		return name;
	}
	//使用并发map作为缓存,transformedBeanNameCache中进行do...while进行截取
	return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
		do {
			beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
		} while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
		return beanName;
	});
}

别名转换委托给SimpleAliasRegistry类canonicalName来进行转换,代码如下:

public String canonicalName(String name) {
  String canonicalName = name;
     String resolvedName;
     //链式转换,一直寻找到最顶级的beanName,在生成BeanDefinition时,最顶级的beanName是在第一位
     do {
         resolvedName = this.aliasMap.get(canonicalName);
         if (resolvedName != null) {
             canonicalName = resolvedName;
         }
     } while (resolvedName != null);
     return canonicalName;
 }

2、三个缓存中获取bean实例:getSingleton

Object sharedInstance = getSingleton(beanName);

Spring中对于单例的bean是采用三个缓存分别来实现bean的管理,一级缓存(singletonObjects)、二级缓存(earlySingletonObjects)、三级缓存(singletonFactories)。

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

三种缓存作用如下:

(1)一级缓存singletonObjects主要是存储spring中一些实例化完成好的bean,也是常说的IOC容器,实际上就是一个并发map;
(2)二级缓存earlySingletonObjects主要是存储提前暴露的,未完成好的bean,如循环依赖时属性未注入时的bean;
(3)三级缓存singletonFactories主要是为了解决循环依赖,保存一些bean的创建单例时的ObjectFactory,用于获得bean。

getSingleton方法是委托DefaultSingletonBeanRegistry类来实现,默认支持单例循环依赖,具体代码如下:

 public Object getSingleton(String beanName) {
	return getSingleton(beanName, true);//支持bean的循环依赖
}
   protected Object getSingleton(String beanName, boolean allowEarlyReference) {
       //从一级缓存中先尝试获取bean
	Object singletonObject = this.singletonObjects.get(beanName);
	//判断是否已从一级缓存中获取到bean和单例bean检查
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {//添加内置锁synchronized并发
		    //在一级缓存中未获得bean时,再从二级缓存中获取提前暴露bean
			singletonObject = this.earlySingletonObjects.get(beanName);
			//二级缓存中是否获得到bean和是否支持循环依赖
			if (singletonObject == null && allowEarlyReference) {
			    //从三级缓存中尝试获取bean的Factory
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
				    //调用ObjectFactory中getObject方法来得到bean
					singletonObject = singletonFactory.getObject();
					//将得到的半成品bean放置到二级缓存
					this.earlySingletonObjects.put(beanName, singletonObject);
					//从三级缓存中移除创建bean的Factory,A和B互相依赖A->B时,三级缓存将A将自身放入,等创建B时直接获取A并将其移除
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

3、递归获取bean:getParentBeanFactory

自定义容器与spring的AbstractBeanFactory递归获取bean,父类容器中获取bean即AbstractBeanFactory中的doGetBean,此处其实是防止自定义容器实现doGetBean中未找到则在AbstractBeanFactory容器中再次获取,代码如下:

BeanFactory parentBeanFactory = getParentBeanFactory();//获取父类容器
   if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
       //获取beanName,此处与transformedBeanName获取beanName不同,会返回普通bean和工厂bean的beanName
       String nameToLookup = originalBeanName(name);
       if (parentBeanFactory instanceof AbstractBeanFactory) {
           /**
            * 父类容器中获取bean即AbstractBeanFactory中的doGetBean,此处其实是防止自定义容器实现doGetBean中未找到
            * 则在AbstractBeanFactory容器中再次获取
            */
           return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                   nameToLookup, requiredType, args, typeCheckOnly);
       } else if (args != null) {
           // 有参数args时则委托给父类容器获取bean
           return (T) parentBeanFactory.getBean(nameToLookup, args);
       } else if (requiredType != null) {
           // 无参数时且requiredType不为空也委托给父类容器获取bean
           return parentBeanFactory.getBean(nameToLookup, requiredType);
       } else {
           //不满足上述if和else if条件时则默认使用父类容器获取bean
           return (T) parentBeanFactory.getBean(nameToLookup);
       }
   }

4、优化缓存bean:markBeanAsCreated

private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

spring在创建bean前会处理下该bean是否允许重复创建即合并覆盖原有的bean,使用alreadyCreated变量(Set)存储防止重复,代码如下:

 protected void markBeanAsCreated(String beanName) {
       if (!this.alreadyCreated.contains(beanName)) {
           synchronized (this.mergedBeanDefinitions) {
               if (!this.alreadyCreated.contains(beanName)) {//该beanName未被创建过
                   clearMergedBeanDefinition(beanName);//将BeanDefinition中的stale设置为true,代表允许再次创建
                   this.alreadyCreated.add(beanName);//将其加入到已创建过集合set中即alreadyCreated
               }
           }
       }
   }
 protected void clearMergedBeanDefinition(String beanName) {
      RootBeanDefinition bd = this.mergedBeanDefinitions.get(beanName);
      if (bd != null) {
          bd.stale = true;//改变BeanDefinition中stale值,可以合并创建
      }
  }

5、depends-on依赖实例化:isDependent

isDependent方法检查该bean是否有循环依赖,如果存在相互先实例化的关系则抛出异常,此处的depend-on属性中是指当前bean实例化之前必须先实例化该属性值中bean,与我们常说的循环依赖是不一样的,该处仅仅是检查该bean必须在另一个bean实例化的前面,可以被注入也可以不被注入。
具体代码如下:

private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
      if (alreadySeen != null && alreadySeen.contains(beanName)) {
          return false;
      }
      //规范化bean,此处仅仅是别名转换,无FactoryBean的前缀去除
      String canonicalName = canonicalName(beanName);
      //依赖集合中获取是否存在先后实例化的关系
      Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
      if (dependentBeans == null) {
          return false;
      }
      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;
  }

6、创建bean:createBean

单例bean创建是getSingleton重载方法且传入的是lamda表达式传入,而创建prototype、request或session作用域bean的时候,是直接调用createBean方法,具体代码如下:

protected Object createBean(String beanName,RootBeanDefinition mbd,Object[] args)
		throws BeanCreationException {
	RootBeanDefinition mbdToUse = mbd;
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);//返回bean的class类型
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}
	try {
	    //预处理方法覆盖的方法,lookup-method和replaced-method两个属性
		mbdToUse.prepareMethodOverrides();
	} catch (BeanDefinitionValidationException ex) {
		throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
				beanName, "Validation of method overrides failed", ex);
	}
	try {
		/**
		 * 实例化前的后置处理器InstantiationAwareBeanPostProcessor和初始化后的后置处理器BeanPostProcessor
		 * 分别对应postProcessBeforeInstantiation后置方法和postProcessAfterInitialization后置方法
		 */
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	} catch (Throwable ex) {
		throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
				"BeanPostProcessor before instantiation of bean failed", ex);
	}
	try {
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		return beanInstance;
	} catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
		throw ex;
	} catch (Throwable ex) {
		throw new BeanCreationException(
		    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
	}
}

(1)实例化前和初始化后的后置处理器

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
	Object bean = null;
	//检测该bean是否有实例化后置处理器
	if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
		//验证bean是否实际已经被解析完成
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		//验证BeanDefinition中的类型和目标类型是否匹配
			Class<?> targetType = determineTargetType(beanName, mbd);
			if (targetType != null) {
				//实例化前的后置处理器InstantiationAwareBeanPostProcessor->postProcessBeforeInstantiation后置方法
				bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
				if (bean != null) {
				    //BeanPostProcessor->postProcessAfterInitialization后置方法
					bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
				}
			}
		}
		mbd.beforeInstantiationResolved = (bean != null);//将bean实例化成功或失败的结果重新赋值
	}
	return bean;
}

(1)InstantiationAwareBeanPostProcessor后置处理器

bean只要实现了InstantiationAwareBeanPostProcessor后置处理器,那么在加载bean的过程中,所有bean都会被执行实例化前postProcessBeforeInstantiation方法即用户自定义实现InstantiationAwareBeanPostProcessor时会执行该方法,如果子类重写了该方法,那么将执行子类中的方法,代码如下:

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {//获取所有后置处理器
        //只处理实现了InstantiationAwareBeanPostProcessor的后置处理器
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            //执行InstantiationAwareBeanPostProcessor中的实例化前postProcessBeforeInstantiation后置方法
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}

(2)BeanPostProcessor后置处理器

bean只要实现了BeanPostProcessor后置处理器,那么在加载bean的过程中,所有bean都会被执行初始化后postProcessAfterInitialization方法即用户自定义实现BeanPostProcessor时会执行该方法,如果子类重写了该方法,那么将执行子类中的方法,代码如下:

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {
    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {//获取所有后置处理器
        //执行BeanPostProcessor中的初始化后postProcessAfterInitialization后置方法
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

(2)Spring创建创建bean:doCreateBean

createBean->resolveBeforeInstantiation方法中返回的结果如果非空,则代表已经创建了代理对象,代码不会执行doCreateBean,反之则返回一个空对象bean,此时spring知道resolveBeforeInstantiation方法中没有生成代理对象,则开始自身着手创建bean即doCreateBean方法,熟悉干实事的doXXX,代码如下:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);//获取未实例化的bean并去除缓存
	}
	if (instanceWrapper == null) {
	    /**
	     * 缓存中未获得实例化wrapper手动创建,spring提供了三种实例化bean的方式,取决于用户指定那种实例化方式
	     * (1)工厂类创建
	     * (2)bean的类有多个构造函数,会根据参数自动匹配
	     * (3)spring使用默认的无参构造函数实例化
	     */
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	Object bean = instanceWrapper.getWrappedInstance();//实例化bean
	Class<?> beanType = instanceWrapper.getWrappedClass();//获取class对象
	if (beanType != NullBean.class) {
		mbd.resolvedTargetType = beanType;
	}
	synchronized (mbd.postProcessingLock) {
		if (!mbd.postProcessed) {
			try {
			    //与上述实例化前和初始化后的后置处理器模式类似
			    //此处是执行MergedBeanDefinitionPostProcessor后置处理器中的postProcessMergedBeanDefinition后置方法
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			} catch (Throwable ex) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Post-processing of merged bean definition failed", ex);
			}
			mbd.postProcessed = true;
		}
	}

	//提前暴露未完整的bean,主要是处理当前正在创建的bean且存在循环依赖时,将自身放入三级缓存中,解决循环依赖
	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));
	}
	Object exposedObject = bean;
	try {
	    //属性注入,前面实例化的bean进行属性填充,请关注后续文章
		populateBean(beanName, mbd, instanceWrapper);
		//执行一些后置处理器如BeanNameAware、BeanFactoryAware等Aware后置方法调用
		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);
		}
	}
	//earlySingletonExposure根据执行的逻辑判断循环依赖是否需要检查
	if (earlySingletonExposure) {
	    //从getSingleton中获取bean,false代表不从三级缓存中获得,此处只从一级和二级缓存获取
		Object earlySingletonReference = getSingleton(beanName, false);
		if (earlySingletonReference != null) {//判断是否存在,如果不为空则代表有循环依赖
			if (exposedObject == bean) {
				exposedObject = earlySingletonReference;
			} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {//是否存在已经被其他bean依赖注入过
				String[] dependentBeans = getDependentBeans(beanName);//获取依赖
				Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
				for (String dependentBean : dependentBeans) {
					if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {//删除仅仅用于类型检查的依赖
						actualDependentBeans.add(dependentBean);//删除失败则代表有除了类型检查以外的其他用途,此时需要记录下来
					}
				}
				//actualDependentBeans有值,代表上述for循环中发现bean已被用于其他用途,循环依赖检查抛出异常
				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.");
				}
			}
		}
	}
	try {
	    //对于是否配置bean的destory-method方法进行处理,注册时将销毁方法也注册进去,如果没有配置则使用spring默认的销毁方法
		registerDisposableBeanIfNecessary(beanName, bean, mbd);
	} catch (BeanDefinitionValidationException ex) {
		throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
	}
	return exposedObject;
}

7、获取bean的实例:getObjectForBeanInstance

getObjectForBeanInstance方法在doGetBean中被多次调用,主要是从缓存中、spring手动创建并返回实例后再次被调用,用于检测该bean的引用是FactoryBean或普通bean实例,如果是工厂bean,则需要调用工厂bean的getObject,返回bean的实例,代码如下:

protected Object getObjectForBeanInstance(Object beanInstance,String name,String beanName,RootBeanDefinition mbd) {
	//检查name是否是自带“&”的工厂bean
	if (BeanFactoryUtils.isFactoryDereference(name)) {
		if (beanInstance instanceof NullBean) {
			return beanInstance;
		}
		if (!(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
		}
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		return beanInstance;
	}

	// beanInstance判断是普通bean则直接返回
	if (!(beanInstance instanceof FactoryBean)) {
		return beanInstance;
	}

	Object object = null;
	if (mbd != null) {
		mbd.isFactoryBean = true;
	} else {
		object = getCachedObjectForFactoryBean(beanName);//从缓存中获取
	}
	if (object == null) {
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
		if (mbd == null && containsBeanDefinition(beanName)) {
			mbd = getMergedLocalBeanDefinition(beanName);
		}
		boolean synthetic = (mbd != null && mbd.isSynthetic());
		//若object为空则从FactoryBean的引用中调用getObject获得bean实例
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-10 11:43:27  更:2022-05-10 11:43:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:11:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码