• [置顶] Spring的DI依赖实现分析


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

    未完,待续

  • 相关阅读:
    软件工程师的悲哀
    关于ControlTemplate 2
    DataTemplate总结2(学习)
    ObjectiveC——类
    6 Popular Ideas That Fail
    Develop Cross Platform Mobile App
    DP 与 DO(学习)
    Titanium颜色总结
    Illustrator Tips
    Titanium API
  • 原文地址:https://www.cnblogs.com/aukle/p/3235408.html
Copyright © 2020-2023  润新知