博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring源码系列:依赖注入(一)getBean
阅读量:6622 次
发布时间:2019-06-25

本文共 5236 字,大约阅读时间需要 17 分钟。

在文章中我们谈到了BeanFactory这容器,这个里面提供了注入的实现接口。其具体的实现还需要从AbstractBeanFactory和DefaultListableBeanFactory中来看。今天就先撸一下AbstractBeanFactory这个类中的getBean这个方法。

1、getBean方法

getBean提供了四个重载方法,如下:

//通过name获取Bean@Overridepublic Object getBean(String name) throws BeansException {	return doGetBean(name, null, null, false);}//通过name和类型获取Bean@Overridepublic 
T getBean(String name, Class
requiredType) throws BeansException { return doGetBean(name, requiredType, null, false);}//通过name和对象参数获取Bean@Overridepublic Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false);}//通过name、类型和参数获取Beanpublic
T getBean(String name, Class
requiredType, Object... args) throws BeansException { return doGetBean(name, requiredType, args, false);}复制代码

从这四个重载方法的方法体中可以看出,他们都是通过doGetBean来实现的。所以doGetBean其实才是真正获取Bean的地方,也是触发依赖注入发生的地方。(这个方法比较长,分段来说)

2、doGetBean

先来看下方法的定义:

@SuppressWarnings("unchecked")	protected 
T doGetBean( final String name, final Class
requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {复制代码
  • name 要检索的bean的名称
  • requiredType 要检索的bean所需的类型
  • args 使用显式参数创建bean实例时使用的参数(仅在创建新实例时应用,而不是在检索现有实例时应用)
  • typeCheckOnly 是否为类型检查而获得实例,而不是实际使用
//返回bean名称,剥离工厂引用前缀,并将别名解析为规范名称。final String beanName = transformedBeanName(name);//声明当前需要返回的bean对象Object bean;// 先从缓存中获取bean,处理已经被创建的单例模式的bean,//对于此类bean的请求不需要重复的创建(singleton)Object sharedInstance = getSingleton(beanName);复制代码

如果当前获取到的sharedInstance不为null并且参数为空,则进行FactoryBean的相关处理,并获取FactoryBean的处理结果。

if (sharedInstance != null && args == null) {	if (logger.isDebugEnabled()) {	    //返回指定的singleton bean是否正在创建(在整个工厂内)。		if (isSingletonCurrentlyInCreation(beanName)) {			logger.debug("Returning eagerly cached instance of singleton bean '" 			+ beanName +"' that is not fully initialized yet - a consequence of a circular reference");		}		else {			logger.debug("Returning cached instance of singleton bean '" + beanName + "'");		}	}	//完成FactoryBean的相关处理,并用来获取FactoryBean的处理结果	bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}复制代码

如果当前获取到的sharedInstance为null,我们再来看下做了哪些处理(下面的都在一个大的else里面):

else {    //分解到下面}复制代码
//在当前线程中,返回指定的prototype bean是否正在创建。if (isPrototypeCurrentlyInCreation(beanName)) {	throw new BeanCurrentlyInCreationException(beanName);}复制代码

下面这段的作用是对Ioc容器中的BeanDefinition是否存在进行检测,先是检测当前BeanFactory中是否能够获取到,如果取不到则继续到双亲容器中进行尝试获取,如果双亲还是取不到,则继续向上一级父容器中尝试获取。

// 检查该工厂是否存在bean定义。BeanFactory parentBeanFactory = getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {	// 如果没有,则继续检查父类	String nameToLookup = originalBeanName(name);	if (args != null) {		// 用明确的参数代表父项。		return (T) parentBeanFactory.getBean(nameToLookup, args);	}	else {		// 如果没有args - >委托给标准的getBean方法。		return parentBeanFactory.getBean(nameToLookup, requiredType);	}}复制代码

将指定的bean标记为已经创建(或即将创建);这里允许bean工厂优化其缓存以重复创建指定的bean。

if (!typeCheckOnly) {	markBeanAsCreated(beanName);}复制代码

先根据beanName来获取BeanDefinition,然后获取当前bean的所有依赖bean,这里是通过递归调用getBean来完成,直到没有任何依赖的bean为止。

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);//检查给定的合并bean定义,可能抛出验证异常。checkMergedBeanDefinition(mbd, beanName, args);// 保证当前bean依赖的bean的初始化。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 + "'");		}		registerDependentBean(dep, beanName);		//递归处理依赖bean		getBean(dep);	}}复制代码

下面这段就是创建一个bean实例;这里通过调用getSingleton方法来创建一个单例bean实例;从代码中可以看到,getSingleton的调用是通过getObject这个回调函数来间接调用createBean完成的。

if (mbd.isSingleton()) {	sharedInstance = getSingleton(beanName, new ObjectFactory() {	//回调函数getObject		@Override		public Object getObject() throws BeansException {			try {			    //创建bean				return createBean(beanName, mbd, args);			}			catch (BeansException ex) {				//发生异常则销毁				destroySingleton(beanName);				throw ex;			}		}	});	//获取给定bean实例的对象,无论是bean实例本身,还是FactoryBean创建的对象。	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}复制代码

下面是创建prototype bean

else if (mbd.isPrototype()) {    Object prototypeInstance = null;    try {    	beforePrototypeCreation(beanName);    	//创建prototype bean    	prototypeInstance = createBean(beanName, mbd, args);    }    finally {    	afterPrototypeCreation(beanName);    }    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}复制代码

最后是对创建的bean进行类型检查,没有问题就返回已经创建好的bean;此时这个bean是包含依赖关系的bean

if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {	try {		return getTypeConverter().convertIfNecessary(bean, requiredType);	}	catch (TypeMismatchException ex) {		if (logger.isDebugEnabled()) {			logger.debug("Failed to convert bean '" + name + "' to required type '" +					ClassUtils.getQualifiedName(requiredType) + "'", ex);		}		throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());	}}//返回beanreturn (T) bean;复制代码

getBean是依赖注入的起点,从上面的分析可以看出,bean的创建都是通过createBean来完成具体的创建的。createBean的具体实现是在AbstractAutowireCapableBeanFactory中的,这里createBean不仅仅负责创建bean,还需要完成对bean的初始化。

转载地址:http://bvjpo.baihongyu.com/

你可能感兴趣的文章
ASP.NET 5 入门(1) - 建立和开发ASP.NET 5 项目
查看>>
spring+activemq中多个consumer同时处理消息时遇到的性能问题
查看>>
git clone 遇到的坑
查看>>
linux系统/var/log目录下的信息详解
查看>>
Android中利用LinearLayout继承实现ImageButton 转
查看>>
图片处理--边缘高亮
查看>>
Linux计划任务Crontab实例详解教程
查看>>
android之布局
查看>>
自定义服务器控件(处理不同的浏览器)
查看>>
解决IE6-IE7下li上下间距
查看>>
配置级别greenplum 可用空间计算
查看>>
聚集索引更新后会不会马上重新排序
查看>>
幸运大抽奖
查看>>
消除人声的方法
查看>>
Post请求
查看>>
labview 中activex的初步使用方法
查看>>
Jquery 操作Html 控件 CheckBox、Radio、Select 控件
查看>>
JSP与JavaBeans
查看>>
解决Android中TextView首行缩进的问题
查看>>
oracle 查询哪些表分区
查看>>