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);
	}