天天看點

spring源碼--容器的基本實作

spring源碼各版本下載下傳位址:

<a href="https://github.com/spring-projects/spring-framework/tags" target="_blank">    https://github.com/spring-projects/spring-framework/tags</a>

在工作中見得非常多的容器使用是:

<code>&lt;beans xmlns=</code><code>"http://www.springframework.org/schema/beans"</code>

<code>    </code><code>xmlns:xsi=</code><code>"http://www.w3.org/2001/XMLSchema-instance"</code> <code>xmlns:util=</code><code>"http://www.springframework.org/schema/util"</code>

<code>    </code><code>xmlns:jee=</code><code>"http://www.springframework.org/schema/jee"</code> <code>xmlns:aop=</code><code>"http://www.springframework.org/schema/aop"</code>

<code>    </code><code>xmlns:tx=</code><code>"http://www.springframework.org/schema/tx"</code> <code>xmlns:context=</code><code>"http://www.springframework.org/schema/context"</code>

<code>    </code><code>xmlns:p=</code><code>"http://www.springframework.org/schema/p"</code> <code>xmlns:cache=</code><code>"http://www.springframework.org/schema/cache"</code>

<code>    </code><code>xmlns:task=</code><code>"http://www.springframework.org/schema/task"</code>

<code>    </code><code>xsi:schemaLocation="</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/task </code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/task/spring-task-4.1.xsd</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/beans</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/beans/spring-beans-4.1.xsd</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/aop </code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/aop/spring-aop-4.1.xsd</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/tx</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/tx/spring-tx-4.1.xsd</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/context</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/context/spring-context-4.1.xsd</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/util </code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/util/spring-util-4.1.xsd</code>

<code>    </code><code>http:</code><code>//www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.1.xsd"&gt;</code>

<code>    </code><code>&lt;bean id=</code><code>"adapConsumer"</code> <code>class</code><code>=</code><code>"com.ad.jms.AdapConsumer"</code><code>&gt;</code>

<code>          </code><code>&lt;property name=</code><code>"queueChannel"</code> <code>ref=</code><code>"inputFromKafkaAdap"</code><code>&gt;&lt;/property&gt;</code>

<code>    </code><code>&lt;/bean&gt;</code>

<code>&lt;/beans&gt;</code>

<code>final</code> <code>ApplicationContext app = </code><code>new</code> <code>ClassPathXmlApplicationContext(</code><code>"applicationContext.xml"</code><code>);</code>

<code>AdapConsumer adConsumer = app.getBean(</code><code>"adapConsumer"</code><code>, AdapConsumer.</code><code>class</code><code>);</code>

其底層實作原理是怎樣的?根據《Spring源碼深度解析》以另外一個容器BeanFactory來解析源碼實作。

一、可以發現BeanFactory是通過XmlBeanFactory建立的,而XmlBeanFactory繼承了DefaultListableBeanFactory,主要增加了XMLBeanDefinitionReader,接下來先認識一下這兩個類。

    1.1 DefaultListableBeanFactory

其中各個類的作用

    1.2 XMLBeanDefinitionReader

完成了對配置檔案進行封裝後配置檔案的讀取工作。

二、我們根據BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"))來分析建立過程

    2.1 new ClassPathResource("beanFactoryTest.xml")

這是通過ClassPathResource構造函數來構造一個ReSource,然後交給XmlBeanFactory的構造函數。那麼ClassPathResource怎麼處理的?

ReSource底層實作:

    2.2 new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"))

<code>public</code> <code>class</code> <code>XmlBeanFactory </code><code>extends</code> <code>DefaultListableBeanFactory {</code>

<code>   </code><code>private</code> <code>final</code> <code>XmlBeanDefinitionReader reader = </code><code>new</code> <code>XmlBeanDefinitionReader(</code><code>this</code><code>);</code>

<code>   </code><code>public</code> <code>XmlBeanFactory(Resource resource) </code><code>throws</code> <code>BeansException {</code>

<code>      </code><code>this</code><code>(resource, </code><code>null</code><code>);</code>

<code>   </code><code>}</code>

<code>   </code><code>public</code> <code>XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) </code><code>throws</code> <code>BeansException {</code>

<code>      </code><code>super</code><code>(parentBeanFactory);</code>

<code>      </code><code>this</code><code>.reader.loadBeanDefinitions(resource);</code>

<code>      </code> 

<code>}</code>

<code>//最後一句代碼主要完成下面三個功能</code>

可以看到有XMLBeanDefinitionReader對象(完成了對配置檔案進行封裝後配置檔案的讀取工作),就是加載bean,在代碼中一層一層往下看:

<code>public</code> <code>int</code> <code>loadBeanDefinitions(Resource resource) </code><code>throws</code> <code>BeanDefinitionStoreException {</code>

<code>   </code><code>return</code> <code>loadBeanDefinitions(</code><code>new</code> <code>EncodedResource(resource));</code>

<code>public</code> <code>int</code> <code>loadBeanDefinitions(EncodedResource encodedResource) </code><code>throws</code> <code>BeanDefinitionStoreException {</code>

<code>   </code><code>Assert.notNull(encodedResource, </code><code>"EncodedResource must not be null"</code><code>);</code>

<code>   </code><code>if</code> <code>(logger.isInfoEnabled()) {</code>

<code>      </code><code>logger.info(</code><code>"Loading XML bean definitions from "</code> <code>+ encodedResource.getResource());</code>

<code>   </code><code>Set&lt;EncodedResource&gt; currentResources = </code><code>this</code><code>.resourcesCurrentlyBeingLoaded.get();</code>

<code>   </code><code>if</code> <code>(currentResources == </code><code>null</code><code>) {</code>

<code>      </code><code>currentResources = </code><code>new</code> <code>HashSet&lt;&gt;(</code><code>4</code><code>);</code>

<code>      </code><code>this</code><code>.resourcesCurrentlyBeingLoaded.set(currentResources);</code>

<code>   </code><code>if</code> <code>(!currentResources.add(encodedResource)) {</code>

<code>      </code><code>throw</code> <code>new</code> <code>BeanDefinitionStoreException(</code>

<code>            </code><code>"Detected cyclic loading of "</code> <code>+ encodedResource + </code><code>" - check your import definitions!"</code><code>);</code>

<code>   </code><code>try</code> <code>{</code>

<code>      </code><code>InputStream inputStream = encodedResource.getResource().getInputStream();</code>

<code>      </code><code>try</code> <code>{</code>

<code>         </code><code>InputSource inputSource = </code><code>new</code> <code>InputSource(inputStream);</code>

<code>         </code><code>if</code> <code>(encodedResource.getEncoding() != </code><code>null</code><code>) {</code>

<code>            </code><code>inputSource.setEncoding(encodedResource.getEncoding());</code>

<code>         </code><code>}</code>

<code>         </code><code>return</code> <code>doLoadBeanDefinitions(inputSource, encodedResource.getResource());</code>

<code>      </code><code>}</code>

<code>      </code><code>finally</code> <code>{</code>

<code>         </code><code>inputStream.close();</code>

<code>   </code><code>catch</code> <code>(IOException ex) {</code>

<code>            </code><code>"IOException parsing XML document from "</code> <code>+ encodedResource.getResource(), ex);</code>

<code>   </code><code>finally</code> <code>{</code>

<code>      </code><code>currentResources.remove(encodedResource);</code>

<code>      </code><code>if</code> <code>(currentResources.isEmpty()) {</code>

<code>         </code><code>this</code><code>.resourcesCurrentlyBeingLoaded.remove();</code>

上面這段代碼真正進入了資料的準備階段執行下面正式進入核心部分:

<code>doLoadBeanDefinitions(inputSource, encodedResource.getResource())</code>

doLoadBeanDefinitions之是以很核心,因為做了三件重要的事情:

<code>protected</code> <code>int</code> <code>doLoadBeanDefinitions(InputSource inputSource, Resource resource)</code>

<code>      </code><code>throws</code> <code>BeanDefinitionStoreException {</code>

<code>      </code><code>Document doc = doLoadDocument(inputSource, resource);</code>

<code>      </code><code>return</code> <code>registerBeanDefinitions(doc, resource);</code>

<code>   </code><code>catch</code> <code>(BeanDefinitionStoreException ex) {</code>

<code>      </code><code>throw</code> <code>ex;</code>

<code>   </code><code>catch</code> <code>(SAXParseException ex) {</code>

<code>      </code><code>throw</code> <code>new</code> <code>XmlBeanDefinitionStoreException(resource.getDescription(),</code>

<code>            </code><code>"Line "</code> <code>+ ex.getLineNumber() + </code><code>" in XML document from "</code> <code>+ resource + </code><code>" is invalid"</code><code>, ex);</code>

<code>   </code><code>catch</code> <code>(SAXException ex) {</code>

<code>            </code><code>"XML document from "</code> <code>+ resource + </code><code>" is invalid"</code><code>, ex);</code>

<code>   </code><code>catch</code> <code>(ParserConfigurationException ex) {</code>

<code>      </code><code>throw</code> <code>new</code> <code>BeanDefinitionStoreException(resource.getDescription(),</code>

<code>            </code><code>"Parser configuration exception parsing XML from "</code> <code>+ resource, ex);</code>

<code>            </code><code>"IOException parsing XML document from "</code> <code>+ resource, ex);</code>

<code>   </code><code>catch</code> <code>(Throwable ex) {</code>

<code>            </code><code>"Unexpected exception parsing XML document from "</code> <code>+ resource, ex);</code>

<code>protected</code> <code>Document doLoadDocument(InputSource inputSource, Resource resource) </code><code>throws</code> <code>Exception {</code>

<code>   </code><code>return</code> <code>this</code><code>.documentLoader.loadDocument(inputSource, getEntityResolver(), </code><code>this</code><code>.errorHandler,</code>

<code>         </code><code>getValidationModeForResource(resource), isNamespaceAware());</code>

<code>public</code> <code>int</code> <code>registerBeanDefinitions(Document doc, Resource resource) </code><code>throws</code> <code>BeanDefinitionStoreException {</code>

<code>   </code><code>BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();</code>

<code>   </code><code>int</code> <code>countBefore = getRegistry().getBeanDefinitionCount();</code>

<code>   </code><code>documentReader.registerBeanDefinitions(doc, createReaderContext(resource));</code>

<code>   </code><code>return</code> <code>getRegistry().getBeanDefinitionCount() - countBefore;</code>

接下來将這三件事情逐個分析:

    2.2.1 擷取xml檔案的驗證模式

    DTD和XSD的差別:

    驗證模式的讀取:

<code>protected</code> <code>int</code> <code>getValidationModeForResource(Resource resource) {</code>

<code>   </code><code>int</code> <code>validationModeToUse = getValidationMode();</code>

<code>   </code><code>if</code> <code>(validationModeToUse != VALIDATION_AUTO) {</code>

<code>      </code><code>return</code> <code>validationModeToUse;</code>

<code>   </code><code>int</code> <code>detectedMode = detectValidationMode(resource);</code>

<code>   </code><code>if</code> <code>(detectedMode != VALIDATION_AUTO) {</code>

<code>      </code><code>return</code> <code>detectedMode;</code>

<code>   </code><code>// Hmm, we didn't get a clear indication... Let's assume XSD,</code>

<code>   </code><code>// since apparently no DTD declaration has been found up until</code>

<code>   </code><code>// detection stopped (before finding the document's root tag).</code>

<code>   </code><code>return</code> <code>VALIDATION_XSD;</code>

    2.2.2 讀取document

<code>protected</code> <code>Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {</code>

<code>package</code> <code>org.springframework.beans.factory.xml;</code>

<code>import</code> <code>org.w3c.dom.Document;</code>

<code>import</code> <code>org.xml.sax.EntityResolver;</code>

<code>import</code> <code>org.xml.sax.ErrorHandler;</code>

<code>import</code> <code>org.xml.sax.InputSource;</code>

<code>public</code> <code>interface</code> <code>DocumentLoader {</code>

<code>   </code><code>Document loadDocument(</code>

<code>         </code><code>InputSource inputSource, EntityResolver entityResolver,</code>

<code>         </code><code>ErrorHandler errorHandler, </code><code>int</code> <code>validationMode, </code><code>boolean</code> <code>namespaceAware)</code>

<code>         </code><code>throws</code> <code>Exception;</code>

    2.2.3 根據傳回的document注冊bean資訊

registerBeanDefinitions方法:

解析并注冊BeanDefinition

本文轉自 叫我北北 51CTO部落格,原文連結:http://blog.51cto.com/qinbin/2059124