[置顶] Spring的DI依赖实现分析
DI(依赖注入)是Spring最底层的核心容器要实现的功能之一,利用DI可以实现程序功能的控制反转(控制反转即程序之间之间的依赖关系不再由程序员来负责,而是由Spring容器来负责)
一个简单的例子(DI例子)
一个接口的源代码(表示一个人说话)
package com.pp;
public interface SaySentence {
public void say();
}
一个类实现了上面的接口,表示要说的一句具体话
package com.pp;
public class Person {
private Sentence sce;
private String name;
public Person(String name,Sentence sce){
this.name=name;
this.sce=sce;
}
public Person(){}
public Sentence getSce() {
return sce;
}
public void setSce(Sentence sce) {
this.sce = sce;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void say(){
/*如果没有DI机制,可能要说一句话就得如下
*Sentenct sce=new SaySentence();
*sce.say();
*或者由程序员显示调用setSentence()方法设置sce
*或者由程序员通过构造函数的方式对sce显示赋值
* */
sce.say();
}
}
Spring的配置文件(person.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="sentence" class="com.pp.Sentence"/>
<bean id="person" class="com.pp.Person">
<constructor-arg value="pp"/>
<constructor-arg ref="sentence"/>
</bean>
</beans>
测试的源代码
package com.pp;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class MainTest {
public static void main(String[] args) {
BeanFactory factory=new XmlBeanFactory(new ClassPathResource("person.xml"));
Person person=(Person)factory.getBean("person");
person.say();
}
}
看到上面的,你应该也了解了什么是IOC,什么是DI,可是我想分析的不是这,这真的很简单,我想分析就是这个DI是怎么实现的:)下面代码,只是摘录,太多了,只贴出几个关键函数,有兴趣的,可以共同分析
//加载的Bean定义
//参数是一个资源文件,这个资源文件指定了编码方式
//返回值是配置文件中的bean定义个数
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
//断言要解析的XML文件配置存在,不能为空
Assert.notNull(encodedResource, "EncodedResource must not be null");
//向日志系统输出日志系统,输出XML bean的加载源
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
//获取当前线程里的ThreadLocal里的变量集合
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
//如果为空的情况下,重新申请一下HashSet集合
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
//将encodeResource填加到当前线程的局部变量集合中
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
//如果设置了编译方式,对输入流进行编码的设置
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
//释放内存空间
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
上面这个函数最关键的部分是doLoadBeanDefinitions这个函数,看看它的源代码
//真正的从指定的XML文件中加载Bean的定义
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//获取资源的校验模式
int validationMode = getValidationModeForResource(resource);
//文档定义
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
这个函数最关键部分是这个registerBeanDefinitions,跟踪到里面,略去源代码,直接分析其最核心的代码registerBeanDefinitions
核心源码如下
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
//向日志文件输出日志信息
logger.debug("Loading bean definitions");
//获取根元素
Element root = doc.getDocumentElement();
//以下是对Xml文件进行解析(各种解析,各种提取)
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
preProcessXml(root);
parseBeanDefinitions(root, delegate);
postProcessXml(root);
}
未完,待续
[置顶] Spring的DI依赖实现分析的更多相关文章
- [置顶] Spring中DI设置器注入
Java的反射机制可以说是在Spring中发挥的淋漓尽致,下面要看的代码就是通过反射机制来实现向一个类注入其实际依赖的类型,这个过程的实现会交由Spring容器来帮我们完成. JavaBean中针对属 ...
- spring+IOC+DI+AOP优点分析(一)
Spring是什么: Spring是一个轻量级的DI和AOP容器框架. 说它轻量级有一大部分原因是相对与EJB的(虽然本人从没有接触过EJB的应用),重要的是,Spring是非侵入式的,基于sprin ...
- Spring:DI依赖注入的几种方式
据我所学,spring实现依赖注入(DI)的方式分为三大类:基于构造器(构造方法)的依赖注入.基于setter的依赖注入.其他方式(c命名空间.p命名空间等).其中推荐使用setter方法注入,这种注 ...
- 3、Spring的DI依赖注入
一.DI介绍 1.DI介绍 依赖注入,应用程序运行依赖的资源由Spring为其提供,资源进入应用程序的方式称为注入. Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为&qu ...
- Spring学习——DI(依赖注入)
IOC容器,处理对象依赖关系 IOC与DI: IOC :是一个容器,创建对象的容器 DI :在容器创建对象后,处理对象的依赖关系,也叫依赖注入! 方式1:通过set方法注入值 可以给普通属性.集合属性 ...
- [置顶]
spring集成mina 实现消息推送以及转发
spring集成mina: 在学习mina这块时,在网上找了很多资料,只有一些demo,只能实现客户端向服务端发送消息.建立长连接之类.但是实际上在项目中,并不简单实现这些,还有业务逻辑之类的处理以及 ...
- [置顶] Spring的自动装配
采用构造函数注入,以及setter方法注入都需要写大量的XML配置文件,这时可以采用另一种方式,就是自动装,由Spring来给我们自动装配我们的Bean. Spring提供了四种自动装配类型 1:By ...
- [置顶] Spring中自定义属性编辑器
Spring中的属性编辑器能够自动的将String类型转化成需要的类型,例如一个类里面的一个整型属性,在配置文件中我们是通过String类型的数字进行配置的,这个过程中就需要一个转化操作,当然这个转化 ...
- [置顶] Firefox OS 学习——Gaia 编译分析
Gaia作为用户的接口,也是用户可见部分,一些用户的应用也是安装在这一层,所以研究他是很有必要的,对于像我这样的初学者,最直接的学习方法就是通过修改代码,然后可以看到UI的变化,很直观的观察修改结果. ...
随机推荐
- 数据结构(左偏树):HDU 1512 Monkey King
Monkey King Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tota ...
- 数学(FFT):BZOJ 3527 [Zjoi2014]力
题目在这里:http://wenku.baidu.com/link?url=X4j8NM14MMYo8Q7uPE7-7GjO2_TXnMFA2azEbBh4pDf7HCENM3-hPEl4mzoe2w ...
- 光学字符识别OCR
1.功能: 光学字符识别(OCR,Optical Character Recognition)是指对文本资料进行扫描,然后对图像文件进行分析处理,获取文字及版面信息的过程 2.典型应用: 名片扫描 3 ...
- [置顶] ruby变量详解(收集+整理)
ruby的变量有局部变量,全局变量,实例变量,类变量,常量. 1.局部变量 局部变量以一个小写字母开头或下划线开头 局部变量有局部作用域限制(比如一个block内),它的作用域起始于声明处,结束于该声 ...
- springmvc框架原理分析
第一步:用户发起请求到前端控制器(DispatcherServlet) 第二步:前端控制器请求HandlerMapping查找Handler,可以根据xml配置,注解进行查找 第三步:处理器映射器Ha ...
- Spring 配置中的 default-lazy-init属性
spring的容器是提供了lazy-load的,即默认的缺省设置是bean没有lazy-load,该属性处于false状态,这样导致spring在启动过程导致在启动时候,会默认加载整个对象实例图,从初 ...
- 351. Android Unlock Patterns
这个题我真是做得想打人了卧槽. 题目不难,就是算组合,但是因为是3乘3的键盘,所以只需要从1和2分别开始DFS,结果乘以4,再加上5开始的DFS就行了. 问题是这个傻逼题目的设定是,从1到8不需要经过 ...
- Miller-Rabin质数测试
Miller-Rabin质数测试 本文主要讨论使用Miller-Rabin算法编写素数的判定算法,题目来源于hihocoder. 题目 题目要求 时间限制:10000ms 单点时限:1000ms 内存 ...
- [转]Android实现计时与倒计时(限时抢购)的几种方法
在购物网站的促销活动中一般都有倒计时限制购物时间或者折扣的时间,这些都是如何实现的呢? 在一个安卓客户端项目中恰好遇到了类似的问题,一开始使用的是Timer与 TimerTask, 虽然此方法通用,但 ...
- Android 省市县 三级联动(android-wheel的使用)[转]
转载:http://blog.csdn.net/lmj623565791/article/details/23382805 今天没事跟群里面侃大山,有个哥们说道Android Wheel这个控件,以为 ...