文档章节

Spring源码阅读-BeanFactory-对象创建注入doCreateBean

Small-Liu
 Small-Liu
发布于 2017/01/10 20:54
字数 1234
阅读 114
收藏 0

前面只是简单说了创建对象的流程,到doCreateBean中才进入到真实创建对象的部分,去掉一些异常判断,一个对象的创建主要有以下几部分,先看总代码,再依次分析:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
	// Instantiate the bean.
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
		//1. 创建对象
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
	Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

	//...

	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
		//2. 填充对象   这个里面解析了依赖的bean
		populateBean(beanName, mbd, instanceWrapper);
		if (exposedObject != null) {
			//3. 初始化方法
			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);
		}
	}

	//...

	// Register bean as disposable.
	try {
		//4. 注册销毁方法
		registerDisposableBeanIfNecessary(beanName, bean, mbd);
	} catch (BeanDefinitionValidationException ex) {
		throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature",
				ex);
	}
	return exposedObject;
}

一 创建对象

这步就是根据class生成对象,对象内存空间就是这边完成的,最终把BeanDefinition转换成BeanWrapper,spring根据创建对象的方法不同走了不同的分支逻辑,看createBeanInstance代码流程:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
	// Make sure bean class is actually resolved at this point.
	Class<?> beanClass = resolveBeanClass(mbd, beanName);

	//...
	
	//工厂方法创建对象
	if (mbd.getFactoryMethodName() != null) {
		//factory-method, 方法需要时static型的
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}

	// Shortcut when re-creating the same bean...
	boolean resolved = false;
	boolean autowireNecessary = false;
	//注意这里的args是通过getBean传的,不传为空
	if (args == null) {
		synchronized (mbd.constructorArgumentLock) {
			//如果构造方法已经解析好则获取默认,缓存作用,后面解析出来会存放进来
			if (mbd.resolvedConstructorOrFactoryMethod != null) {
				resolved = true;
				autowireNecessary = mbd.constructorArgumentsResolved;
			}
		}
	}
	//如果构造方法已经解析
	if (resolved) {
		if (autowireNecessary) {
			return autowireConstructor(beanName, mbd, null, null);
		} else {
			return instantiateBean(beanName, mbd);
		}
	}

	//获取对应的有参构造方法
	// Need to determine the constructor...
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR
			|| mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	// 没有解析到有参构造方法则使用默认无参构造方法
	// No special handling: simply use no-arg constructor.
	return instantiateBean(beanName, mbd);
}
  1. 先解析class,确保创建对象之前Class已经生成
  2. 如果配置了factory-method,则用对应的工厂方法创建,进入instantiateUsingFactoryMethod
  3. 根据参数找到对应构造方法,根据构造方法依赖注入,这里寻找对应的构造方法花费了很多精力,找到构造方法后进入autowireConstructor方法
  4. 没有参数则用默认构造方法构造instantiateBean

上面创建对象有三个分支:工厂方法、有参构造方法、无参构造方法, 它处理逻辑是相似的,先找到对应生成实例的方法和方法的参数,在根据策略实例化对象, 这两个工作spring又分别委托给了两个角色处理:

  1. ConstructorResolver,解析生成实例的方法和方法参数,工厂模式解析的是对象的工厂方法,构造方法模式解析的时候对应的构造方法,无参构造方法这边省略了。
  2. InstantiationStrategy,实例化对象的策略,无overrides走反射,有overrides用cglib生成

二 填充对象

这个里面就是设置依赖属性了,看下面精简过的代码:

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
	//这个是配置文件中的,后面根据策略获取非配置文件中的
	PropertyValues pvs = mbd.getPropertyValues();

	//...

	//可以在bean配置里面设置autowire类型
	if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME
			|| mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

		//根据名称解析,配置文件配置autowire="byName"
		// Add property values based on autowire by name if applicable.
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
			autowireByName(beanName, mbd, bw, newPvs);
		}
		//根据类型解析
		// Add property values based on autowire by type if applicable.
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
			autowireByType(beanName, mbd, bw, newPvs);
		}

		pvs = newPvs;
	}

	//...
	
	//设置属性
	applyPropertyValues(beanName, mbd, bw, pvs);
}

可以在配置文件中用property标签配置,可以用autowire="byName(byType)"属性配置,最终获取的需要依赖对象都放到PropertyValues中,后通过applyPropertyValues设置依赖对象。注意:这里的autowire标签属性要跟@Autowired区分,@Autowired是2.5以加入通过注解简化配置的功能,这个后续再看。

三 初始化对象

这步首先把Aware类型的注入了:

private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
		//子类判断
		if (bean instanceof BeanNameAware) {
			//beanName设置
			((BeanNameAware) bean).setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware) {
			//classLoader设置
			((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
		}
		if (bean instanceof BeanFactoryAware) {
			//bean工厂设置
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

其次,调用初始化方法,如果实现了InitializingBean则执行afterPropertiesSet方法,如果有自定义方法则调用自定义方法。

四 注册销毁方法

如果单例情况并且有销毁方法,则把bean注册到对应的销毁bean集合,在对象工厂shutdown的时候调用,如果是非原形的其他scope则由该scope自定义销毁策略。

 

补充:在上面这四个步骤之间穿插着一些BeanPostProcessors的调用,这是spring的开闭原则,后续要统一看一下。

 

© 著作权归作者所有

Small-Liu
粉丝 17
博文 56
码字总数 49976
作品 0
南京
程序员
私信 提问
Spring IOC 实现原理

Spring IOC 实现原理 IOC: Inversion of Control ,即 "控制反转" , 不是什么技术,而是一种思想。原先需要自行实例化的对象, 交给IOC容器去实现。那么控制反转,谁被控制? 谁被反转 ? 在...

起个名忒难
2018/05/17
0
0
Spring IOC 容器源码分析(二)

从篇章一到这里是一个分水岭,前面的内容都还算比较简单,大家要清楚地知道前面都做了哪些事情。 Bean 容器实例化完成后 说到这里,我们回到 refresh() 方法,我重新贴了一遍代码,看看我们说...

小码哥的freestyle
04/06
0
0
Spring Ioc 源码分析(二)- bean的实例化

在 Spring Ioc 源码分析(一)- XML 解析 中,我们完成了从 xml 到 BeanDefinition的过程。只是把 xml描述的 Bean定义转换为 Java对象描述。本文将讲解 spring 如何利用 BeanDefinition 完成...

我叫董先森
2017/10/19
18
0
通过循环引用问题来分析Spring源码

本文主要分析Spring的循环依赖问题。开始正文之前,我们需要定义这2个类。LoopReferenceA中引用LoopReferenceB,LoopReferenceB中引用LoopReferenceA。 分析 AbstractApplicationContext中的...

cmazxiaoma
2018/08/24
0
0
Spring IoC源码解析(二)——Bean的创建和初始化

上节回顾 上一节,我们分析了Spring IoC容器是如何去初始化一个BeanFactory的,同时也分析了BeanFactory是如何去加载spring.xml中的的bean。本质上就是BeanFactory是如何去初始化BeanDefinni...

Jia
2016/10/27
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

Blockstack-2 :Blockstack ID注册

本篇文章主要记录Blockstack ID注册的流程; 在介绍注册流程之前,先简单的介绍一下Blockstack ID; 相对于传统互联网来说,Blockstack ID更像是统一的账号系统;即一个账号即可登录和授权所...

Riverzhou
40分钟前
8
0
面试官问:平时碰到系统CPU飙高和频繁GC,你会怎么排查?

处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及Full GC次数过多的问题。当然,这些问题的最终导致的直观现象就是系统运行缓慢,并且有大量的报警。本文主要针对系统运...

Java高级架构师n
今天
23
0
面向对象编程

1、类和对象 类是对象的蓝图和模板,而对象是实例;即对象是具体的实例,类是一个抽象的模板 当我们把一大堆拥有共同特征的对象的静态特征(属性)和动态特征(行为)都抽取出来后,就可以定...

huijue
今天
23
0
redis异常解决 :idea启动本地redis出现 jedis.exceptions.JedisDataException: NOAUTH Authentication required

第一次安装在本地redis服务,试试跑项目,结果却出现nested exception is redis.clients.jedis.exceptions.JedisDataException: NOAUTH Authentication required错误,真是让人头疼 先检查一...

青慕
今天
35
0
Spring 之 IoC 源码分析 (基于注解方式)

一、 IoC 理论 IoC 全称为 Inversion of Control,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection),即依赖注入。 二、IoC方式 Spring为IoC提供了2种方式,一种是基于xml...

星爵22
今天
34
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部