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. C#验证码使用

    1.C#创建验证码 1.1 创建获取验证码页面(ValidateCode.aspx) <html xmlns="http://www.w3.org/1999/xhtml"&g ...

  2. hdu 3062 2-sat入门题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3062 #include <cstdio> #include <cmath> # ...

  3. 使用MyEclipse实现简单的Servlet程序

    1. 创建一个继承于GenericServlet的类 3. 重写Server方法 package cn.school; import java.io.IOException; import javax ...

  4. Java调用R(三)_系统命令调用

    java通过配置的系统命令Rscript直接调用R脚本. 优点:R脚本和Java代码完全分离 缺点:R中变量不能控制 1. Java本地能够成功调用. public void CallR() { Ru ...

  5. js dom操作获取节点的一些方法

    在复习javascript基础的时候,整理了一下js中获取节点的一些常用的方法,见代码: //js获取下一个兄弟节点 function getNextSibling(eleObj){ var next ...

  6. web容器线程数和程序中线程阻塞导致 请求超时

    问题描述: web项目启动之后.调用dubbo的远程服务. 但是有个基础服务报错. 当并发访问用户量上来之后. dubbo服务的报错返回 比正常服务慢 不能正常消费服务 清理服务线程. 也就是dubb ...

  7. WebService-通俗讲解

    一.序言 大家或多或少都听过 WebService(Web服务),有一段时间很多计算机期刊.书籍和网站都大肆的提及和宣传WebService技术,其中不乏很多吹嘘和做广告的成 分.但是不得不承认的是W ...

  8. SAP-Basic:使用SCC1时提示 TA263“集团被集团副本锁定用于输入”

    错误信息   消息号TA263   解决方法 Step 1.使用SCC4进入"集团管理"界面. Step 2.双击要维护的集团,例如"010",进入详细配置界面 ...

  9. Swift-Lesson2(下)

  10. CSU1661: Query Mutiple

    Description One day,Little-Y saw many numbers standing in a row. A question suddenly appeared in her ...