阅读更多

企业架构
论坛精华 啃啃老菜:Spring IOC核心源码学习(一)  

2012-03-07  作者 singleant  编辑 luiang1018 有53861人浏览

啃啃老菜:Spring IOC核心源码学习(一)

 

本文主要以spring ioc容器基本代码骨架为切入点,理解ioc容器的基本代码组件结构,各代码组件细节剖析将放在后面的学习文章里。

 

关于IOC容器

IoC容器:最主要是完成了完成对象的创建和依赖的管理注入等等。

先从我们自己设计这样一个视角来考虑:

所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。

对象和对象关系怎么表示?

可以用xmlproperties文件等语义化配置文件表示。

描述对象关系的文件存放在哪里?

可能是classpathfilesystem,或者是URL网络资源,servletContext等。

回到正题,有了配置文件,还需要对配置文件解析。

不同的配置文件对对象的描述不一样,如标准的,自定义声明式的,如何统一? 在内部需要有一个统一的关于对象的定义,所有外部的描述都必须转化成统一的描述定义。

如何对不同的配置文件进行解析?需要对不同的配置文件语法,采用不同的解析器。

 

基于以上问题,对应过来,刚好是 spring ioc 容器抽象的的几个主要接口:

Resource

BeanDefinition

BeanDefinitionReader

BeanFactory

ApplicationContext

以上五个都是接口,都有各式各样的实现,正是这5个接口定义了spring ioc容器的基本代码组件结构。而其组件各种实现的组合关系组成了一个运行时的具体容器。

 

各代码组件详解

1.Resource

是对资源的抽象,每一个接口实现类都代表了一种资源类型,如ClasspathResourceURLResourceFileSystemResource等。每一个资源类型都封装了对某一种特定资源的访问策略。它是spring资源访问策略的一个基础实现,应用在很多场景。

 

 

 

 

具体可以参考文章:

Spring 资源访问剖析和策略模式应用

http://www.ibm.com/developerworks/cn/java/j-lo-spring-resource/index.html

 

 

2.BeanDefinition

用来抽象和描述一个具体bean对象。是描述一个bean对象的基本数据结构。

3.BeanDefinitionReader

BeanDefinitionReader将外部资源对象描述的bean定义统一转化为统一的内部数据结构BeanDefinition。对应不同的描述需要有不同的Reader。如XmlBeanDefinitionReader用来读取xml描述配置的bean对象。



 

4.BeanFactory

用来定义一个很纯粹的bean容器。它是一个bean容器的必备结构。同时和外部应用环境等隔离。BeanDefinition是它的基本数据结构。它维护一个BeanDefinitions Map,并可根据BeanDefinition的描述进行bean的创建和管理。



 

5.ApplicationContext

从名字来看叫应用上下文,是和应用环境息息相关的。没错这个就是我们平时开发中经常直接使用打交道的一个类,应用上下文,或者也叫做spring容器。其实它的基本实现是会持有一个BeanFactory对象,并基于此提供一些包装和功能扩展。为什么要这么做呢?因为BeanFactory实现了一个容器基本结构和功能,但是与外部环境隔离。那么读取配置文件,并将配置文件解析成BeanDefinition,然后注册到BeanFactory的这一个过程的封装自然就需要ApplicationContextApplicationContext和应用环境细细相关,常见实现有ClasspathXmlApplicationContext,FileSystemXmlApplicationContext,WebApplicationContext等。ClasspathxmlFileSystemWeb等词都代表了应用和环境相关的一些意思,从字面上不难理解各自代表的含义。

当然ApplicationContextBeanFactory的区别远不止于此,有:

1.  资源访问功能:在ResourceResourceLoader的基础上可以灵活的访问不同的资源。

2.  支持不同的信息源。

3.  支持应用事件:继承了接口ApplicationEventPublisher,这样在上下文中为bean之间提供了事件机制。

……



 

 

以上5个组件基本代表了ioc容器的一个最基本组成,而组件的组合是放在ApplicationContext的实现这一层来完成。

 

以ClasspathXmlApplicationContext 容器实现为例,其组合关系如下:

 


ClassPathXmlApplicationContext的refresh() 方法负责完成了整个容器的初始化。

为什么叫refresh?也就是说其实是刷新的意思,该IOC容器里面维护了一个单例的BeanFactory,如果bean的配置有修改,也可以直接调用refresh方法,它将销毁之前的BeanFactory,重新创建一个BeanFactory。所以叫refresh也是能理解的。

以下是Refresh的基本步骤:
1.把配置xml文件转换成resource。resource的转换是先通过ResourcePatternResolver来解析可识别格式的配置文件的路径
(如"classpath*:"等),如果没有指定格式,默认会按照类路径的资源来处理。
2.利用XmlBeanDefinitionReader完成对xml的解析,将xml Resource里定义的bean对象转换成统一的BeanDefinition。
3.将BeanDefinition注册到BeanFactory,完成对BeanFactory的初始化。BeanFactory里将会维护一个BeanDefinition的Map。

当getBean的时候就会根据调用BeanFactory,根据bean的BeanDifinition来实例化一个bean。当然根据bean的lazy-init、protetype等属性设置不同以上过程略有差别。

 

refresh()代码如下:

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				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.
				registerListeners();

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

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				// Destroy already created singletons to avoid dangling resources.
				beanFactory.destroySingletons();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}
		}
	}

 以上的obtainFreshBeanFactory是很关键的一个方法,里面会调用loadBeanDefinition方法,如下:

	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws 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.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);
	}

 LoadBeanDifinition方法很关键,这里特定于整个IOC容器,实例化了一个XmlBeanDefinitionReader来解析Resource文件。关于Resource文件如何初始化和xml文件如何解析都在

loadBeanDefinitions(beanDefinitionReader);

 里面的层层调用完成,这里不在累述。

小结 

Spring的扩展性是毋庸置疑的,学习spring的设计是一个很好的实践理论结合。主要个人觉得有几点:

1.  框架顶层的设计有着很好的抽象,遵循面向接口编程的规范。ResourceBeanFactoryApplicationContext都是非常好的接口抽象,非常明确的定义了该组件的一些功能。

2.  利用组合模式。

3.  个组件的实现里大量使用了模板方法模式,提升了同一组件代码的复用性。

4.  各种设计保留了扩展的接口,很多基于spring的框架都可以很容易的介入实现了自己的一些扩展。

5.  框架里采用里很多经典的设计模式,如代理、装饰、策略等等。

 

 

 



相关推荐

  • APACHE 自定义404错误页面设置方法

    方法一:  在httpd.conf中设置对目录开启。  AllowOverride All  然后在目录里放一个.htaccess(.htaccess),添加:  errorDocument 404 /404....如果web目录下有多个项目,必须在每个项目下都有.htaccess,里面填

  • SEO优化 - 使用nginx为网站设置自定义404错误页

    当打开错误页面的时候返回404页面,404页面需要有返回首页的连接,提高搜索引擎友好度; 例如访问 http://www.laker.com/test.html,其实这个页面是没有的,或者禁止访问的,使其返回404响应码,相应返回404错误页。 ...

  • .htaccess 404错误页面自定义详解

    一般来说,默认的404页面是不返回任何数据,IE浏览器中会提示“找不到该页 该页无法显示”,但是你会发现有一些网站,即使是找不到页面,也能显示一个非常有艺术的404页面。我之前的一篇文章简单的归纳了一下,查看...

  • .htaccess设置404时,ie浏览器失败

    在非ie浏览器中可以正常跳转到设置好的404页面,在ie终究不显示,提示比较经典的‘找不到页面’。 从网上搜索一些资料获得问题的根源,及解决方法:用户自定义的404页面大小必须大于512字节,否则ie浏览器会认为...

  • iis php 404错误页面,IIS自定义404错误页面

    404、503错误相信大多数站长朋友很对很熟悉,网站刚刚搭建完成后我们一般都会做一个404和503错误页面。那么这是怎么操作的呢?熟悉我的朋友们一定会记得我前段时间写的一篇...对于Apache的404错误页面自定义设...

  • centos7 php 404,CentOS7 Apache环境配置自定义404错误页面怎么解决

    我的万云数据ECS用的 CentOS 7系统,我想在网站实现 自定义的 404页面,之前已经做了 伪静态,现在 修改了 根目录的 .htaccess, 也加了 404.html 在根目录,但是随机访问一个错误页面。不会设置404请看下面方案方法...

  • php apache 404,Apache开启404自定义面页、PHP输出404错误

    作者:elinstudio发布时间:July 18, 2012分类:Web服务器过增加.htaccess:在httpd.conf中设置对目录开启伪静态。AllowOverride All然后在目录里放一个.htaccess(.htaccess),添加:ErrorDocument 404 /404.html这...

  • html网页运行出现404错误,网页无法进入404错误是什么情况?怎么办? 爱问知识人...

    当这些错误得到标准化时,Web服务器处理404错误的方法最终就取决于网络管理员。这就是为什么将其称之为可配置。最为通用的Web服务器软件,Apache,通过位于public_html目录下的小文本文件。htaccess来控制HTTP错误的...

  • Apache自定义404错误页面的方法

    通过增加.htaccess: 在httpd.conf中设置对目录开启。 AllowOverride All 然后在目录里放一个.htaccess(....可是有时候当你用IE浏览的时候会发现,这玩意压根就不跳转,关键的地方就是这个html,如果404.htm...

  • 详解Apache下.htaccess文件常用配置

    .htaccess文件是Apache服务器中最常用...通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置索引入口等功能。  另外,.h

  • APACHE_自定义404错误页面

    在httpd.conf中设置对目录开启。 ? 1  AllowOverride All  然后在目录里放一个.htaccess(.htaccess),添加: ? 1  errorDocument...

  • Apache自定义404错误页面

    方法一1、在httpd.conf中(如果你是Vhost,那么修改httpd-vhost.conf下相应的地方)设置对目录开启允许Override。AllowOverride All2、在目录里放一个.htaccess文件,添加下面一行:ErrorDocument 404 /error.html这...

  • Apache之404错误页面自定义跳转说明

    404错误其实就是我们经常见到的找不到文件的错误,但是那是默认的效果,很难看。有时候我们需要的这样的功能:我们要记录下来404是的页面时哪些,更有些时候我需要判断404页面是不是本来系统应该生成的静态页面但是...

  • apache特殊页面的设置(404,500)

    一:读取.htaccess文件 开启rewrite模块 找到#LoadModule rewrite_module modules/mod_rewrite.so然后把前面的#去掉 < IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d ...

  • 级联H桥SVG无功补偿系统在不平衡电网中的三层控制策略:电压电流双闭环PI控制、相间与相内电压均衡管理,级联H桥SVG无功补偿系统在不平衡电网中的三层控制策略:电压电流双闭环PI控制、相间与相内电压均

    级联H桥SVG无功补偿系统在不平衡电网中的三层控制策略:电压电流双闭环PI控制、相间与相内电压均衡管理,级联H桥SVG无功补偿系统在不平衡电网中的三层控制策略:电压电流双闭环PI控制、相间与相内电压均衡管理,不平衡电网下的svg无功补偿,级联H桥svg无功补偿statcom,采用三层控制策略。 (1)第一层采用电压电流双闭环pi控制,电压电流正负序分离,电压外环通过产生基波正序有功电流三相所有H桥模块直流侧平均电压恒定,电流内环采用前馈解耦控制; (2)第二层相间电压均衡控制,注入零序电压,控制通过注入零序电压维持相间电压平衡; (3)第三层相内电压均衡控制,使其所有子模块吸收的有功功率与其损耗补,从而保证所有H桥子模块直流侧电压值等于给定值。 有参考资料。 639,核心关键词: 1. 不平衡电网下的SVG无功补偿 2. 级联H桥SVG无功补偿STATCOM 3. 三层控制策略 4. 电压电流双闭环PI控制 5. 电压电流正负序分离 6. 直流侧平均电压恒定 7. 前馈解耦控制 8. 相间电压均衡控制 9. 零序电压注入 10. 相内电压均衡控制 以上十个关键词用分号分隔的格式为:不

  • GTX 1080 PCB图纸

    GTX 1080 PCB图纸,内含图纸查看软件

  • 深度优化与应用:提升DeepSeek润色指令的有效性和灵活性指南

    内容概要:本文档详细介绍了利用 DeepSeek 进行文本润色和问答交互时提高效果的方法和技巧,涵盖了从明确需求、提供适当上下文到尝试开放式问题以及多轮对话的十个要点。每一部分内容都提供了具体的示范案例,如指定回答格式、分步骤提问等具体实例,旨在指导用户更好地理解和运用 DeepSeek 提升工作效率和交流质量。同时文中还强调了根据不同应用场景调整提示词语气和风格的重要性和方法。 适用人群:适用于希望通过优化提问技巧以获得高质量反馈的企业员工、科研人员以及一般公众。 使用场景及目标:本文针对所有期望提高 DeepSeek 使用效率的人群,帮助他们在日常工作中快速获取精准的答案或信息,特别是在撰写报告、研究材料准备和技术咨询等方面。此外还鼓励用户通过不断尝试不同形式的问题表述来进行有效沟通。 其他说明:该文档不仅关注实际操作指引,同样重视用户思维模式转变——由简单索取答案向引导 AI 辅助创造性解决问题的方向发展。

  • 基于FPGA与W5500实现的TCP网络通信测试平台开发-Zynq扩展口Verilog编程实践,基于FPGA与W5500芯片的TCP网络通信测试及多路Socket实现基于zynq开发平台和Vivad

    基于FPGA与W5500实现的TCP网络通信测试平台开发——Zynq扩展口Verilog编程实践,基于FPGA与W5500芯片的TCP网络通信测试及多路Socket实现基于zynq开发平台和Vivado 2019软件的扩展开发,基于FPGA和W5500的TCP网络通信 测试平台 zynq扩展口开发 软件平台 vivado2019.2,纯Verilog可移植 测试环境 压力测试 cmd命令下ping电脑ip,同时采用上位机进行10ms发包回环测试,不丢包(内部数据回环,需要时间处理) 目前实现单socket功能,多路可支持 ,基于FPGA; W5500; TCP网络通信; Zynq扩展口开发; 纯Verilog可移植; 测试平台; 压力测试; 10ms发包回环测试; 单socket功能; 多路支持。,基于FPGA与W5500的Zynq扩展口TCP通信测试:可移植Verilog实现的高效网络通信

  • Labview液压比例阀伺服阀试验台多功能程序:PLC通讯、液压动画模拟、手动控制与调试、传感器标定、报警及记录、自动实验、数据处理与查询存储,报表生成与打印一体化解决方案 ,Labview液压比例阀

    Labview液压比例阀伺服阀试验台多功能程序:PLC通讯、液压动画模拟、手动控制与调试、传感器标定、报警及记录、自动实验、数据处理与查询存储,报表生成与打印一体化解决方案。,Labview液压比例阀伺服阀试验台多功能程序:PLC通讯、液压动画模拟、手动控制与调试、传感器标定、报警管理及实验自动化,labview液压比例阀伺服阀试验台程序:功能包括,同PLC通讯程序,液压动画,手动控制及调试,传感器标定,报警设置及报警记录,自动实验,数据处理曲线处理,数据库存储及查询,报表自动生成及打印,扫码枪扫码及信号录入等~ ,核心关键词:PLC通讯; 液压动画; 手动控制及调试; 传感器标定; 报警设置及记录; 自动实验; 数据处理及曲线处理; 数据库存储及查询; 报表生成及打印; 扫码枪扫码。,Labview驱动的智能液压阀测试系统:多功能控制与数据处理

  • 华为、腾讯、万科员工职业发展体系建设与实践.pptx

    华为、腾讯、万科员工职业发展体系建设与实践.pptx

Global site tag (gtag.js) - Google Analytics