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); }
未完,待续