【Spring源码第二天】ApplicationContext源码

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


spring源码阅读第一天

在理解大致Bean生命周期后,继续从源码层面去了解整个流程;很常规的:最重要的就是AbstractApplicationContext中的refresh方法;

源码阅读入口,debug调试:


ApplicationContext ac = new ClassPathXmlApplicationContext(config);

1. 扫描配置文件

可以走进ClassPathXmlApplicationContext的构造方法:

public ClassPathXmlApplicationContext(
		String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
		throws BeansException {

	super(parent);  // 调用父类的构造创建一个Xml的容器
	setConfigLocations(configLocations);  // 设置配置文件路径
	if (refresh) {
		refresh();  // 核心方法
	}
}

2. refresh()方法

之后就可以进入 refresh()方法,通过14个方法调用完成整个bean的创建流程,整个方法的执行对于各阶段来说可以分为:准备 -》 创建

2.1 prepareRefresh()

进行刷新前的准备工作,项目启动的环境:

protected void prepareRefresh() {
	this.startupDate = System.currentTimeMillis();
	this.closed.set(false);
	this.active.set(true);

	// ... 日志打印

	// Initialize any placeholder property sources in the context environment.
	// 空实现,由子类实现
	initPropertySources();

	// 获取系统环境  new StandardEnvironment();
	getEnvironment().validateRequiredProperties();

	// Store pre-refresh ApplicationListeners...
	if (this.earlyApplicationListeners == null) {
		this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
	}
	else {
		this.applicationListeners.clear();
	this.applicationListeners.addAll(this.earlyApplicationListeners);
	}
	// 添加事件集
	this.earlyApplicationEvents = new LinkedHashSet<>();
}

在这里插入图片描述

2.2 obtainFreshBeanFactory()

看名字就是获取一个beanFactory工厂;想想bean的生命周期,BeanFactory是整个流程的入口,因此需要提前创建:

protected final void refreshBeanFactory() throws BeansException {
	if (hasBeanFactory()) {  // 如果有工厂销毁,关闭
		destroyBeans();
		closeBeanFactory();
	}
	// 创建一个新的工厂,然后获取
	try {
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		// 为beanFactory设置一些基本属性
		beanFactory.setSerializationId(getId());
		customizeBeanFactory(beanFactory); 
		loadBeanDefinitions(beanFactory);  // 加载beanDefinition对象
		synchronized (this.beanFactoryMonitor) {
			this.beanFactory = beanFactory;
		}
	}
	catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
}

结束后:在这里插入图片描述
这里看beanFactory的实现类是DefaultListenedBeanFactory, 下面是他的继承关系图:
在这里插入图片描述

2.3 prepareBeanFactory

工厂创建结束后,BeanDefinition对象也有了,下一步就应该注入bean工厂,但是想想生命周期,还有一个beanFactoryPostProcessor增强的过程,因此过程如下:
在这里插入图片描述
这里的忽略Aware,前面说过Aware出现在实例化阶段,那么说明对象已经创建完毕了;而在当前方法的作用是用来操作BeanDefinition的,因此需要忽略Aware; 否则对象创建完了,修改BeanDefinition也没什么意义。


2.4 postProcessBeanFactory

空实现,由子类完成;想想实现BeanFactoryPostProcess中的重写方法就是这个 spring源码阅读第一天


2.5 bean实例化前的准备

在这里插入图片描述

2.6 finishBeanFactoryInitialization(重要)

开始进行实例化:

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

在这里插入图片描述
进入preInstantiateSingletons 方法:

// 封装bean信息成一个集合
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

// 合并父子容器的beanDefinition信息,之前创建的BeanDefinition是Generic类型的
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

// 判断是不是FactoryBean,即是否为可自己暴露的工厂
if (isFactoryBean(beanName)) {
	// ... 				
else {
	getBean(beanName);
}

在这里插入图片描述
在调用doGetBean的时候,首先getSingleton先查看缓存
可以先有个印象,spring中存在三级缓存,用来解决循环依赖问题
在这里插入图片描述
对于doGetBean的部分操作之前写过一次(仅针对无参构造bean的注入)
对于概览可以先看一下:Spring Bean的无参构造过程
继续浏览到:
在这里插入图片描述
在这里插入图片描述
doCreateBean中包含:createBeanInstance和populate
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
接着看到结尾:return BeanUtils.instantiateClass(constructorToUse);
在这里插入图片描述
使用反射机制获取无参构造然后创建了bean对象;当然还有很多操作:如循环依赖,是否提前暴露;先有个印象;
使用无参构造的bean中的属性使用默认值,因此有了后面的populate填充属性。
填充属性后,还有一个方法调用,点进去
在这里插入图片描述

总结

至此,普通的bean对象已经创建完成,可返回了;如果使用了FactoryBean,应该还有getObject的方法等;

  1. refresh方法执行逻辑
    在这里插入图片描述
  2. 实例化对象的执行流程
    在这里插入图片描述
    今天的结果是用过浏览源码理解Bean的具体声明周期,走了一遍调用流程;还有很多细节没看,如:
  • 三级缓存解决循环依赖
  • populate的内部实现
  • 暴露对象的意义
  • FactorBean的引入,在实例化对象后的最后getObject方法的含义
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值