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依赖实现分析的更多相关文章

  1. [置顶] Spring中DI设置器注入

    Java的反射机制可以说是在Spring中发挥的淋漓尽致,下面要看的代码就是通过反射机制来实现向一个类注入其实际依赖的类型,这个过程的实现会交由Spring容器来帮我们完成. JavaBean中针对属 ...

  2. spring+IOC+DI+AOP优点分析(一)

    Spring是什么: Spring是一个轻量级的DI和AOP容器框架. 说它轻量级有一大部分原因是相对与EJB的(虽然本人从没有接触过EJB的应用),重要的是,Spring是非侵入式的,基于sprin ...

  3. Spring:DI依赖注入的几种方式

    据我所学,spring实现依赖注入(DI)的方式分为三大类:基于构造器(构造方法)的依赖注入.基于setter的依赖注入.其他方式(c命名空间.p命名空间等).其中推荐使用setter方法注入,这种注 ...

  4. 3、Spring的DI依赖注入

    一.DI介绍 1.DI介绍 依赖注入,应用程序运行依赖的资源由Spring为其提供,资源进入应用程序的方式称为注入. Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为&qu ...

  5. Spring学习——DI(依赖注入)

    IOC容器,处理对象依赖关系 IOC与DI: IOC :是一个容器,创建对象的容器 DI :在容器创建对象后,处理对象的依赖关系,也叫依赖注入! 方式1:通过set方法注入值 可以给普通属性.集合属性 ...

  6. [置顶] spring集成mina 实现消息推送以及转发

    spring集成mina: 在学习mina这块时,在网上找了很多资料,只有一些demo,只能实现客户端向服务端发送消息.建立长连接之类.但是实际上在项目中,并不简单实现这些,还有业务逻辑之类的处理以及 ...

  7. [置顶] Spring的自动装配

    采用构造函数注入,以及setter方法注入都需要写大量的XML配置文件,这时可以采用另一种方式,就是自动装,由Spring来给我们自动装配我们的Bean. Spring提供了四种自动装配类型 1:By ...

  8. [置顶] Spring中自定义属性编辑器

    Spring中的属性编辑器能够自动的将String类型转化成需要的类型,例如一个类里面的一个整型属性,在配置文件中我们是通过String类型的数字进行配置的,这个过程中就需要一个转化操作,当然这个转化 ...

  9. [置顶] Firefox OS 学习——Gaia 编译分析

    Gaia作为用户的接口,也是用户可见部分,一些用户的应用也是安装在这一层,所以研究他是很有必要的,对于像我这样的初学者,最直接的学习方法就是通过修改代码,然后可以看到UI的变化,很直观的观察修改结果. ...

随机推荐

  1. (转载)php curl_init函数用法

    (转载)http://blog.sina.com.cn/s/blog_640738130100tsig.html 使用PHP的cURL库可以简单和有效地去抓网页.你只需要运行一个脚本,然后分析一下你所 ...

  2. 图论(网络流):[CTSC2001]终极情报网

    [CTSC2001]终极情报网 [题目描述] 在最后的诺曼底登陆战开始之前,盟军与德军的情报部门围绕着最终的登陆地点展开了一场规模空前的情报战. 这场情报战中,盟军的战术是利用那些潜伏在敌军内部的双重 ...

  3. 数据结构(RMQ):UVAoj 11235 Frequent values

    Frequent values You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. I ...

  4. UVa11613 Acme Corporation(最小费用流)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=33452 [思路] 最小费用流. 构图: 1 每个月建立2个点,建立 ...

  5. 浅谈二维RMQ

    针对一些二维区间最值问题,用一维RMQ来解决显然是不够的.所以,要改进算法.鉴于网上没有PASCAL版的RMQ标程与解析,所以小可在这里简单的讲一下. 核心思想和一维的一样,只是在计算区间时略有不同. ...

  6. selenium grid 搭建

    hub端 Step1: 下载 selenium-server-standalone-x.xx.x.jar我下载的是:selenium-server-standalone-2.44.0.jar下载地址: ...

  7. Girls' research - HDU 3294 (Manacher处理回文串)

    题目大意:给以一个字符串,求出来这个字符串的最长回文串,不过这个字符串不是原串,而是转换过的,转换的原则就是先给一个字符 例如 'b' 意思就是字符把字符b转换成字符 a,那么c->b, d-& ...

  8. hdu 3698 Let the light guide us(线段树优化&简单DP)

    Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/O ...

  9. Linux cpuinfo 详解

     在Linux系统中,如何详细了解CPU的信息呢? 当然是通过cat /proc/cpuinfo来检查了,但是比如几个物理CPU/几核/几线程,这些问题怎么确定呢? 经过查看,我的开发机器是1个物理C ...

  10. iOS开发系列之运动事件

    前面我们主要介绍了触摸事件以及由触摸事件引出的手势识别,下面我们简单介绍一下运动事件.在iOS中和运动相关的有三个事件:开始运动.结束运动.取消运动. 监听运动事件对于UI控件有个前提就是监听对象必须 ...