当前位置: 首页 > news >正文

Spring源码系列-容器刷新

Spring对于程序员说来说都不陌生;作为一个强大的开源技术,帮助我们能够更好的进行项目的开发与维护。

上次在Spring的启动过程文章中对Spring的启动过程做了一个较为详细的说明和分析。那么在实际的过程中,Spring的启动实际上就是Spring容器的初始化过程。本文将从源码的角度结合自己断点执行过程中保留的现场来分析一下容器的刷新过程(主要分析前几个方法,后面几个会分开来说)。

Spring的启动是通过ContextLoaderListener来进行的,在ContextLoaderListener中通过委托父类ContextLoader的initWebApplicationContext来完成具体的初始化过程。具体的启动过程可以看下之前的那篇文章。

在initWebApplicationContext方法是用来创建容器的,核心代码如下:

今天主要来看configureAndRefreshWebApplicationContext方法中最后的wac.refresh()到底发生了哪些事;

1、obtainFreshBeanFactory:BeanFactory的刷新和创建

refresh()方法主要为IoC容器Bean的生命周期管理提供条件,Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,所以整个refresh()中“ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();”这句以后代码的都是注册容器的信息源和生命周期事件,载入过程就是从这句代码启动。 AbstractApplicationContext的obtainFreshBeanFactory()方法调用子类容器的refreshBeanFactory()方法,启动容器载入Bean定义资源文件的过程。 refresh()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。refresh的作用类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入。 和refreshBeanFactory方法类似,载入Bean定义的方法loadBeanDefinitions也使用了委派模式,在AbstractRefreshableApplicationContext类中只定义了抽象方法,具体的实现调用子类容器中的方法实现。

//通知子类去刷新内部bean 工厂

再来看refreshBeanFactory

此实现执行该上下文的底层bean工厂的实际刷新,关闭以前的bean工厂(如果有的话),并为上下文生命周期的下一阶段初始化一个新的bean工厂。

customizeBeanFactory(DefaultListableBeanFactory beanFactory)

/**
        //通过当前上下文来自定义内部bean工厂<br>
	 * Customize the internal bean factory used by this context.
	 * Called for each {@link #refresh()} attempt.
	 * <p>The default implementation applies this context's
	 * {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
	 * and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
	 * if specified. Can be overridden in subclasses to customize any of
	 * {@link DefaultListableBeanFactory}'s settings.
	 * @param beanFactory the newly created bean factory for this context
	 * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
	 * @see DefaultListableBeanFactory#setAllowCircularReferences
	 * @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
	 * @see DefaultListableBeanFactory#setAllowEagerClassLoading
	 */
	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		if (this.allowBeanDefinitionOverriding != null) {
			beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.allowCircularReferences != null) {
			beanFactory.setAllowCircularReferences(this.allowCircularReferences);
		}
	}
复制代码

XmlWebApplicationContext类中loadBeanDefinitions(beanFactory)

@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}
复制代码

AbstractApplicationContext调用loadBeanDefinitions(DefaultListableBeanFactory beanFactory) ,此方法根据首先创建XmlBeanDefinitionReader对象,然后配置该对象的上下文和资源加载环境,同时调用子类实现的initBeanDefinitionReader对XmlBeanDefinitionReader进行个性化配置,最近后入到initBeanDefinitionReader(beanDefinitionReader)的调用:

  1. 据给定的BeanFactory创建XmlBeanDefinitionReader 对象
  2. 配置beanDefinitionReader的上下文和资源加载环境
  3. 用子类实现的initBeanDefinitionReader对XmlBeanDefinitionReader进行个性化配置initBeanDefinitionReader(beanDefinitionReader);
  4. 调用载入Bean定义的方法,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器

装载bean定义通过XmlBeanDefinitionReader。

// Create a new XmlBeanDefinitionReader for the given BeanFactory. 通过给定的bean工厂创建一个新的XmlBeanDefinitionReader
1.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

2.使用上下文的资源加载环境配置bean定义读取器。
   beanDefinitionReader.setEnvironment(getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
3.允许子类提供reader的自定义初始化,然后继续实际加载bean定义。
    //通过制定的XmlBeanDefinitionReader来载入beandefinitionReader 
   initBeanDefinitionReader(beanDefinitionReader)
   // 通过制定的XmlBeanDefinitionReader来载入bean definitions
   loadBeanDefinitions(beanDefinitionReader)
复制代码

AbstractApplicationContext调用loadBeanDefinitions(beanDefinitionReader),这个方法是取得资源或资源路径然后通过传入的reader去加载BeanDefinitions。

2、loadBeanDefinitions

目前使用Spring的配置都是基于XML的,因此使用XmlBeanDefinitionReader 中的loadBeanDefinitions方法。

看doLoadBeanDefinitions,这个就是具体的读取文件配置,然后注册成Bean

3、prepareBeanFactory

配置工厂的标准上下文特性,如上下文的类装载器和后处理器。

  • 告诉内部bean工厂使用上下文的类装入器等。
  • 上下文回调配置bean工厂。
  • BeanFactory接口未登记为普通工厂的解析式。MessageSource登记(为自动装配创建)作为一个Bean
  • 如果创建;就去寻找LoadTimeWeaver,然后准备组织
  • 注册默认环境bean。

通过断点来看下当前的beanFactory

继续执行...

beanDefinitionMap

manualSingletonNames

4、postProcessBeanFactory

注册web特性的全局域

1).registerWebApplicationScopes

注册具有web特性的域;包括:"request", "session", "globalSession", "application"

看下存储结构:
registerScope方法
2).registerEnvironmentBeans

注册web特性 环境bean(“contextparameters”、“ContextAttribute”)与给定的WebApplicationContext使用BeanFactory。

1.servletContext

2.servletConfig
3.registerSingleton

这里是找到了我们默认的配置文件参数:
beanName=contextParameters

最后是将contextAttributes放入;contextAttributes中包含的属性值比较多,具体如下面所示:

主要包括: javax.servlet.context.tempdir, org.apache.catalina.resources, org.springframework.web.context.support.ServletContextScope, org.apache.tomcat.util.scan.MergedWebXml, org.apache.tomcat.InstanceManager, org.apache.catalina.jsp_classpath, javax.websocket.server.ServerContainer, org.apache.tomcat.JarScanner

这里是把需要的东西全部载入进来了,有很多。就不贴了(mime-mapping)....

5、invokeBeanFactoryPostProcessors

BeanDefinitionRegistryPostProcessor实例化:标准BeanFactoryPostProcessor的扩展,BeanFactoryPostProcessor的作用是用来进一步定义注册的BeanDefinition,IoC容器本质就是Bean管理,所以BeanFactoryPostProcessor本身也是Bean,要对BeanFactoryPostProcessor的BeanDefinition进一步定义就通过BeanDefinitionRegistryPostProcessor进行注册,BeanDefinitionRegistryPostProcessor及其子类是Ioc容器最实例化的一类Bean。它们在ConfigurableApplicationContext(ApplicationContext子接口)实现类调用refresh()方法调用invokeBeanFactoryPostProcessors(beanFactory);方法时就被实例化。

OK,今天关于这部分的分析就到此结束了,后面的过程会在下一篇Spring系列文章中继续来讲refresh中的过程。

祝大家平安夜快乐....

如果您对系列文章有任何意见,可以给我留言,感谢大家。

下面是一个接苹果的姿势,呼呼呼.....

相关文章:

  • WPF用样式实现TextBox的虚拟提示效果
  • ReactiveCocoa学习
  • [POJ2411]Mondriaan's Dream
  • CentOS7防火墙
  • vue.js 初步学习资源
  • Atlassian发布JIRA项目组合管理解决方案
  • 图片后门恶意捆绑工具FackImageexploer
  • php扩展模块安装
  • Android Studio 3.0 Android 分析器 | 中文教学视频
  • GeoIP2 数据库更新地址
  • 个人常用iOS第三方库以及XCode插件介绍
  • 杭州数澜联合创始人 \u0026 CTO 江敏:大数据思维和大数据冶炼 —— 拒绝坐着金山吃馒头...
  • 重磅干货不容错过!2017云栖大会汇总资料,速来领取!
  • Linux—CentOS7,玩转samba服务,基于身份验证的共享
  • initial ram filesystem
  • AHK 中 = 和 == 等比较运算符的用法
  • interface和setter,getter
  • Java面向对象及其三大特征
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • tab.js分享及浏览器兼容性问题汇总
  • Unix命令
  • 不发不行!Netty集成文字图片聊天室外加TCP/IP软硬件通信
  • 诡异!React stopPropagation失灵
  • 基于Android乐音识别(2)
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 通过来模仿稀土掘金个人页面的布局来学习使用CoordinatorLayout
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • Nginx惊现漏洞 百万网站面临“拖库”风险
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • (04)odoo视图操作
  • (20050108)又读《平凡的世界》
  • (超详细)语音信号处理之特征提取
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (十八)SpringBoot之发送QQ邮件
  • (算法)求1到1亿间的质数或素数
  • (五)关系数据库标准语言SQL
  • (五)网络优化与超参数选择--九五小庞
  • (转)scrum常见工具列表
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .net core开源商城系统源码,支持可视化布局小程序
  • .NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)...
  • .NET的数据绑定
  • ??myeclipse+tomcat
  • @reference注解_Dubbo配置参考手册之dubbo:reference
  • @Validated和@Valid校验参数区别
  • [ 隧道技术 ] 反弹shell的集中常见方式(四)python反弹shell
  • [Android]Android开发入门之HelloWorld
  • [APUE]进程关系(下)
  • [C#]手把手教你打造Socket的TCP通讯连接(一)
  • [C\C++]读入优化【技巧】
  • [Cocoa]iOS 开发者账户,联机调试,发布应用事宜