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