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的实例化以及初始化过程? -> 正文阅读

[Java知识库]请你参考源码说一下spring的实例化以及初始化过程?

在这里插入图片描述
开始DeBUG流程:

1、创建beanFactory容器
2、加载配置文件,解析bean定义信息,包装成BeanDefinition
3、执行BeanFactoryPostProcessor

准备工作:准备BeanPostProcessor,广播器,监听器
4、实例化操作
5.初始化操作
6、获取对象


ApplicationContext.refresh()

前戏,做容器刷新前的准备工作
1、设置容器的启动时间
2、设置活跃状态为true
3、设置关闭状态为false
4、获Environment对象,并加载当前系统的属性值到Environment对象中
5、准备监听器和事件的集合对象,默认为空的集合
// Prepare this context for refreshing.
prepareRefresh();
// 创建容器对象: DefaultListableBeanFactory
// 加载xmL配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

	@Override
	protected final void refreshBeanFactory() throws BeansException {
	//如果存在beanFactroy,则销毁beanFactory
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
		// 创建defaultListableBeanFactroy对象
			DefaultListableBeanFactory beanFactory = createBeanFactory(); 
			// 为了序列化制定Id,可以从id反序列化到beanFactroy对象
			beanFactory.setSerializationId(getId());
			// 定制beanFactory 设置相关信息, 包括是否允许覆盖同名称的不同定义的对象,以及循环依赖
			customizeBeanFactory(beanFactory);
			// 初始化documentReader,并进行XML文件读取以及解析, 自定义标签的解析
			loadBeanDefinitions(beanFactory);
			// 执行完之后:步骤2、加载配置文件,解析bean定义信息,包装成BeanDefinition
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

// beanFacotry的准备工作,对各种属性进行填充
prepareBeanFactory(beanFactory);
// allows post-processing of the bean factory in context subclasses.
// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的。
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
// 调用各种beanFactory后置处理器
// 步骤3、执行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册bean处理器,这里只是注册功能,真正调用的是getBean方法
// 准备工作:准备BeanPostProcessor,广播器,监听器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 支持国际化操作
initMessageSource();
// Initialize event multicaster for this context.
// 初始化上下文事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
 onRefresh();
// Check for listener beans and register them.
// 在所有注册的bean中查找Listener bean ,注册到消息广播器中
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有剩余的(非懒加载的)单例。
finishBeanFactoryInitialization(beanFactory);
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();		

List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 当获取到beanName之后,会直接创建吗?先从容器中获取,如果获取不到再创建.
for (String beanName : beanNames) {
	getBean(beanName);
		doGetBean(name, null, null, false);
			createBean(beanName, mbd, args);
				createBean(beanName, mbd, args);
								instanceWrapper = createBeanInstance(beanName, mbd, args);
									{
											Class<?> beanClass = resolveBeanClass(mbd, beanName);
											constructorTouse = clazz . getDeclaredConstructor();
											ctor.newInstance ( argsWithDefaultValues ) ;
}
}	

这时,已经完成了实例化操作:
在这里插入图片描述

接下来,属性填充:但是,beanFactory applicationConext 是通过aware接口设置的,此时没有值。

populateBean(beanName, mbd, instanceWrapper);

在这里插入图片描述

invokeAwareMethods(beanName, bean);

private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof BeanNameAware) {
			((BeanNameAware) bean).setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware) {
			ClassLoader bcl = getBeanClassLoader();
			if (bcl != null) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
			}
		}
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

此时,只有一个赋值,beanFactory:
在这里插入图片描述

wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

在这里插入图片描述
执行初始化方法:

invokeInitMethods(beanName, wrappedBean, mbd);

最后执行一下:

wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

1 Bean的一生从总体上来说可以分为两个阶段:

1、容器启动阶段
2、Bean实例化阶段

1.1 容器的启动阶段都做的是预热工作:

1、配置元信息:Spring IOC容器将对象实例的创建与对象实例的使用分离,业务中需要依赖哪个对象不再依靠我们自己手动创建,Spring就会以注入的方式交给我们需要的依赖对象。Spring需要知道创建一个对象实例所需要的一些必要的信息,而这些必要的信息可以是xml配置文件,也可以是现在主流的注解,创建对象所需要的必要信息称为配置元信息。

2、BeanDefination:Spring在内存中表示这些配置元信息的方式是BeanDefination,配置元信息被加载到内存之后是以BeanDefination的形存在的。

3、BeanDefinationReader:读取xml配置元信息,那么可以使用XmlBeanDefinationReader;要读取properties配置文件,那么可以使用PropertiesBeanDefinitionReader加载;要读取注解配置元信息,那么可以使用 AnnotatedBeanDefinitionReader加载。总的来说,BeanDefinationReader的作用就是加载配置元信息,并将其转化为内存形式的BeanDefination。

4、BeanDefinationRegistry:Spring通过BeanDefinationReader将配置元信息加载到内存生成相应的BeanDefination之后,就将其注册到BeanDefinationRegistry中,是一种键值对的形式,通过特定的Bean定义的id,映射到相应的BeanDefination。

5、BeanFactoryPostProcessor:BeanFactoryPostProcessor是容器启动阶段Spring提供的一个扩展点,主要负责对注册到BeanDefinationRegistry中的一个个的BeanDefination进行一定程度上的修改与替换。例如使用占位符配置元信息,例如配置Jdbc的DataSource连接的时候可以这样配置:

 <property name="driverClassName"  
        value="${jdbc.driverClassName}">  
    </property>  

BeanFactoryPostProcessor就会对注册到BeanDefinationRegistry中的BeanDefination做最后的修改,替换$占位符为配置文件中的真实的数据。至此,整个容器启动阶段就算完成了,容器的启动阶段的最终产物就是注册到BeanDefinationRegistry中的一个个BeanDefination了,这就是Spring为Bean实例化所做的预热的工作:
在这里插入图片描述

1.2 Bean实例化阶段

选择懒加载的方式,那么直到我们伸手向Spring要依赖对象实例之前,其都是以BeanDefinationRegistry中的一个个的BeanDefination的形式存在,也就是Spring只有在我们需要依赖对象的时候才开启相应对象的实例化阶段;而如果我们不是选择懒加载的方式,容器启动阶段完成之后,将立即启动Bean实例化阶段,通过隐式的调用所有依赖对象的getBean方法来实例化所有配置的Bean并保存起来。

1、对象创建策略:对象的创建采用了策略模式,BeanDefinationRegistry中的BeanDefination,我们可以使用反射的方式创建对象,也可以使用CGlib字节码生成创建对象。

2、BeanWrapper:由于Spring IOC容器为了统一对不同类型对象的访问,Spring给所有创建的Bean实例穿上了一层外套BeanWrapper。
BeanWrapper实际上是对反射相关API的简单封装,我们要获取某个对象的属性、调用某个对象的方法,现在不需要在写繁杂的反射API了以及处理一堆麻烦的异常,直接通过BeanWrapper就可以完成相关操作。

3、设置对象属性:对于基本类型的属性,如果配置元信息中有配置,那么将直接使用配置元信息中的设置值赋值即可,即使基本类型的属性没有设置值,属性依然可以被赋予默认的初始化零值;对于引用类型的属性,Spring会将所有已经创建好的对象放入一个Map结构中,此时Spring会检查Map中是否已经有对应对象的实例了。如果有,那么直接注入,如果没有,那么Spring会暂时放下该对象的实例化过程,转而先去实例化依赖对象,再回过头来完成该对象的实例化过程。

这里有一个Spring中的经典问题,那就是Spring是如何解决循环依赖的?

4、检查Aware相关接口:用户自定义的对象想要依赖Spring中的相关对象,那么可以实现相应的Aware接口,Spring IOC容器就会为我们自动注入相关依赖对象实例。

对于BeanFactory来说:先检查相关的Aware接口,然后去Spring的对象池(也就是容器,也就是那个Map结构)中去查找相关的实例(例如对于ApplicationContextAware接口,就去找ApplicationContext实例),也就是说我们必须要在配置文件中或者使用注解的方式,将相关实例注册容器中,BeanFactory才可以为我们自动注入。而对于ApplicationContext,由于其本身继承了一系列的相关接口,所以当检测到Aware相关接口,需要相关依赖对象的时候,ApplicationContext完全可以将自身注入到其中,ApplicationContext实现这一步是通过——BeanPostProcessor。

在这里插入图片描述
例如ApplicationContext继承自ResourceLoader和MessageSource,那么当我们实现ResourceLoaderAware和MessageSourceAware相关接口时,就将其自身注入到业务对象中即可。

5、BeanPostProcessor前置处理:

BeanFactoryPostProcessor存在于容器启动阶段而BeanPostProcessor存在于对象实例化阶段,BeanFactoryPostProcessor关注对象被创建之前 那些配置的修修改改,而BeanPostProcessor阶段关注对象已经被创建之后 的功能增强,替换等操作。

BeanPostProcessor与BeanFactoryPostProcessor都是Spring在Bean生产过程中强有力的扩展点。Spring中著名的AOP(面向切面编程),其实就是依赖BeanPostProcessor对Bean对象功能增强的。

BeanPostProcessor前置处理就是在要生产的Bean实例放到容器之前,允许我们程序员对Bean实例进行一定程度的修改,替换等操作。ApplicationContext对于Aware接口的检查与自动注入就是通过BeanPostProcessor实现的,在这一步Spring将检查Bean中是否实现了相关的Aware接口,如果是的话,那么就将其自身注入Bean中即可。Spring中AOP就是在这一步产生对于原生对象的代理对象,然后将对源对象上的方法调用,转而使用代理对象的相同方法调用实现的。

6、自定义初始化逻辑:在所有的准备工作完成之后,如果我们的Bean还有一定的初始化逻辑,那么Spring将允许我们通过两种方式配置我们的初始化逻辑:一般通过配置init-method方法。

7、BeanPostProcess后置处理:与前置处理类似,这里是在Bean自定义逻辑也执行完成之后,Spring又留给我们的最后一个扩展点。我们可以在这里在做一些我们想要的扩展。

8、自定义销毁逻辑:这一步对应自定义初始化逻辑,同样有两种方式:
实现DisposableBean接口
配置destory-method参数。
这里一个比较典型的应用就是配置dataSource的时候destory-method为数据库连接的close()方法。

9、使用

10、调用回调销毁接口:Spring的Bean在为我们服务完之后,马上就要消亡了(通常是在容器关闭的时候),别忘了我们的自定义销毁逻辑,这时候Spring将以回调的方式调用我们自定义的销毁逻辑,然后Bean就这样走完了光荣的一生!

在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-05 17:11:57  更:2021-08-05 17:14:34 
 
开发: 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年5日历 -2024/5/11 12:42:44-

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