成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Spring源碼一(容器的基本實(shí)現(xiàn)1)

awokezhou / 1483人閱讀

摘要:下面跟蹤代碼到這個(gè)實(shí)現(xiàn)中看看是怎么做的在實(shí)例化的過(guò)程中,在構(gòu)造函數(shù)中調(diào)用了其超類的構(gòu)造函數(shù),而在超類中對(duì)其所處換環(huán)境進(jìn)行的判斷,所謂的環(huán)境呢,事實(shí)上指得就是是通過(guò),還是通過(guò)加載的上下文,這也就意味著不同方式加載可能存在某些不同。

前言

本文基于《Spring源碼深度解析》學(xué)習(xí), 《Spring源碼深度解析》講解的Spring版本低于Spring3.1,當(dāng)前閱讀的版本為Spring5.x,所以在文章內(nèi)容上會(huì)有所不同。
這篇文章基于有一定Spring 基礎(chǔ)的人進(jìn)行講解,所以有些問(wèn)題并不做詳細(xì)的實(shí)現(xiàn), 如有分析不合理或是錯(cuò)誤的地方請(qǐng)指教指正,不勝感激。

一、在非ApplicationContext下使用

在《Spring源碼深度解析》中有這樣一個(gè)實(shí)例:

public class BeanFactoryTest {
    @test
    public void testSimpleLoad() {
        BeanFactory bf = new XmBeanFactory(new ClassPathResource("beanFactoryTest.xml");
        MyTestBean bean = (MyTestBean) bf.getBean("myTestBean");
        assertEquals("testStr", bean.getTestStr());        
    }
}

當(dāng)然在這里會(huì)有一個(gè)Spring的配置文件 beanFactoryTest.xml, 當(dāng)使用xml文件的時(shí)候,會(huì)發(fā)現(xiàn)文件頭有一些
這樣的標(biāo)簽, 建議學(xué)習(xí)一下DOM,DOM2, DOM3結(jié)構(gòu), 以便更加清晰的了解xml文件頭中的內(nèi)容的真正意義。
這里的配置文件只寫一個(gè)相關(guān)的bean

這段代碼的作用就是以下幾點(diǎn):

讀取配置文件。

在Spring的配置中找到bean,并實(shí)例化。

使用斷言判斷實(shí)例的屬性。

@deprecated as of Spring 3.1 in favor of {@link DefaultListableBeanFactory} and {@link XmlBeanDefinitionReader}
這是該類在當(dāng)前版本的部分注釋,在Spring3.1以后這個(gè)類被棄用了,Spring官方不建議使用這個(gè)類。建議使用以上這兩個(gè)類。XmlBeanDefinitionReader本就是以前定義在這個(gè)類中的一個(gè)final的實(shí)例,而DefaultListableBeanFactory則是該類的超類。加載配置文件可以這樣使用:

 Resource resource = new ClassPathResource("beanFactoryTest.xml");
 BeanFactory beanFactory = new DefaultListableBeanFactory();
 BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) beanFactory);
 beanDefinitionReader.loadBeanDefinitions(resource);
 MyTestBean bean = (MyTestBean) bf.getBean("myTestBean");
 assertEquals("testStr", bean.getTestStr());

這個(gè)過(guò)程和上面的過(guò)程實(shí)際上的實(shí)現(xiàn)只用一點(diǎn)不同、前者是在創(chuàng)建時(shí)就直接實(shí)例化了bean, 后者則是在加載的時(shí)候才實(shí)例化bean:

讀取配置文件。

創(chuàng)建BeanFactory。

創(chuàng)建BeanDefinitionReader。

加載resource資源。

獲取bean實(shí)例(實(shí)例化bean)。

使用斷言判斷實(shí)例的屬性。

事實(shí)上在實(shí)際的使用中,絕大多數(shù)時(shí)候都會(huì)通過(guò)以下這種ApplicationContext的方式來(lái)加載Spring的配置文件并進(jìn)行解析, 以后會(huì)寫到這里的實(shí)現(xiàn):

ApplicationContext sc = new ClassPathXmlApplicationContext("applicationContext.xml");

二、加載并解析配置文件
 Resource resource = new ClassPathResource("beanFactoryTest.xml");

通過(guò)ClassPathResource 加載配置文件,并構(gòu)建該實(shí)例的時(shí)候,是使用Resource接口進(jìn)行定義的, 這也就說(shuō)明了創(chuàng)建的實(shí)際上是Resource的實(shí)例,通過(guò)查看Resource 的源碼不難發(fā)現(xiàn),Resource對(duì)Java中將要使用的資源進(jìn)行了抽象,Spring的設(shè)計(jì)中幾乎所有可以加載資源的
類需要直接或間接的實(shí)現(xiàn)Resource 這個(gè)接口。下面可以看一下這個(gè)接口:

boolean exists();    // 判斷是否資源是否存在
default boolean isReadable() {  // 判斷資源是否可讀
    return exists();
}
default boolean isOpen() { // 判斷文件是否打開
    return false;
}
default boolean isFile() { // 判斷文件是否是文件系統(tǒng)中的文件,Spring5.0后加入的
    return false;
}
URL getURL() throws IOException; // 獲取文件的URL

URI getURI() throws IOException; // 獲取文件的URI
File getFile() throws IOException; // 獲取文件
default ReadableByteChannel readableChannel() throws IOException {  // 返回一個(gè)Channel, 擁有最大效率的讀操作
    return Channels.newChannel(getInputStream());
}
long contentLength() throws IOException; // 返回資源解析后的長(zhǎng)度
long lastModified() throws IOException; // 最后一次休干時(shí)間
Resource createRelative(String relativePath) throws IOException; // 基于當(dāng)前資源創(chuàng)建一個(gè)相對(duì)資源
@Nullable
String getFilename(); // 獲取文件名  for example, "myfile.txt"
String getDescription(); // 獲取資源描述, 當(dāng)發(fā)生錯(cuò)誤時(shí)將被打印


通過(guò)查看源碼,還有一點(diǎn)可以發(fā)現(xiàn), Resource接口繼承了InputStreamSource 接口,下面來(lái)看下這個(gè)接口:

public interface InputStreamSource {

    /**
     * Return an {@link InputStream} for the content of an underlying resource.
     * 

It is expected that each call creates a fresh stream. *

This requirement is particularly important when you consider an API such * as JavaMail, which needs to be able to read the stream multiple times when * creating mail attachments. For such a use case, it is required * that each {@code getInputStream()} call returns a fresh stream. * @return the input stream for the underlying resource (must not be {@code null}) * @throws java.io.FileNotFoundException if the underlying resource doesn"t exist * @throws IOException if the content stream could not be opened */ InputStream getInputStream() throws IOException; }

這個(gè)接口的作用非常簡(jiǎn)單并且是頂層接口,它的作用就是返回一個(gè)InputStream, 最簡(jiǎn)單的作用卻提供了最大的方便, 因?yàn)樗匈Y源加載類幾乎都直接或間接的實(shí)現(xiàn)了Resource, 這也就意味著, 幾乎所有的資源加載類都可以得到一個(gè)InputStream, 這將使得在資源加載之后能輕易地得到一個(gè)InputStream, 這非常重要。通過(guò)InputStream, Spring使所有的資源文件都能進(jìn)行統(tǒng)一的管理了, 優(yōu)點(diǎn)是不言而喻的。至于實(shí)現(xiàn)是非常簡(jiǎn)單的, ClassPathResource 中的實(shí)現(xiàn)方式便是通過(guò)class或者classLoader提供的底層方法進(jìn)行調(diào)用的, 對(duì)于FileSystemResource的實(shí)現(xiàn)其實(shí)更加簡(jiǎn)單, 就是直接使用FileInputStream對(duì)文件進(jìn)行實(shí)例化。

三、DefaultListableBeanFactory、XmlBeanDefinitionReader和BeanDefinitionRegistry

配置文件加載完成后進(jìn)行的下一步操作是這樣的,這和3.1之前的版本不太一樣,至于為什么要棄用XmlBeanFactory(我猜是為了對(duì)其他部分進(jìn)行設(shè)計(jì),從而讓這部分代碼更加充分的進(jìn)行解耦):

 BeanFactory beanFactory = new DefaultListableBeanFactory();
 BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) beanFactory);
 beanDefinitionReader.loadBeanDefinitions(resource);

配置文件加載完成后,創(chuàng)建了一個(gè)BeanFactory的實(shí)例。DefaultListableBeanFactory: 見名知意,這是一個(gè)默認(rèn)可列的bean工廠類,注釋用說(shuō)道,典型的一個(gè)應(yīng)用就是在第一次定義時(shí)注冊(cè)所有bean。接下來(lái)的操作是利用多態(tài)將上一步創(chuàng)建的BeanFactory的實(shí)例轉(zhuǎn)成BeanDefinitionRegistry, 因?yàn)橄乱徊叫枰x取xml文件中定義的內(nèi)容,這也就是XmlBeanDefinitionReader的作用,而XmlBeanDefinitionReader在實(shí)例化的時(shí)候需要一個(gè)bean的定義注冊(cè)機(jī),所以就進(jìn)行了以上操作, 事實(shí)上:在創(chuàng)建BeanFactory實(shí)例時(shí),同樣可以定義為BeanDefinitionRegistry類型。下面詳細(xì)說(shuō)下一這三個(gè)類的作用:

DefaultListableBeanFactory:在定義時(shí)通過(guò)當(dāng)前類的類加載器(如果不存在就向上級(jí)加載器尋找直到系統(tǒng)加載器)下的所有的bean進(jìn)行注冊(cè),注意這里只是進(jìn)行注冊(cè)而已。

BeanDefinitionRegistry: 為了注冊(cè)Spring持有的bean的一個(gè)接口,是在BeanFactory,AbstractBeanDefinition中間的一層接口。

XmlBeanDefinitionReader:注釋中這樣寫道

    /**
     * Bean definition reader for XML bean definitions.
     * Delegates the actual XML document reading to an implementation
     * of the {@link BeanDefinitionDocumentReader} interface.
     *
     * 

Typically applied to a * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory} * or a {@link org.springframework.context.support.GenericApplicationContext}. * *

This class loads a DOM document and applies the BeanDefinitionDocumentReader to it. * The document reader will register each bean definition with the given bean factory, * talking to the latter"s implementation of the * {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} interface. */ 只說(shuō)最重要的一個(gè)部分, 在這里它需要委托一個(gè)真正的xml文檔讀取器來(lái)讀取文檔內(nèi)容,也就是BeanDefinitionDocumentReader,而這個(gè)文檔讀取器將讀取所有的bean注冊(cè)內(nèi)容,而這些資源正是1、2中所得到的。

接下來(lái)就是重要的一步,beanDefinitionReader.loadBeanDefinitions(resource); 在解析了配置文件中的bean后,事實(shí)上配置文件中bean并沒有被真正的加載,并且上面的步驟也只是對(duì)所有的bean進(jìn)行了一次注冊(cè), 所以,這個(gè)時(shí)候load了resoure中的內(nèi)容, 在編碼沒有問(wèn)題以后,并且resource中bean可以在類加載器下找到這些類,這時(shí)就對(duì)這些bean進(jìn)行加載,實(shí)例化。下面跟蹤代碼到這個(gè)實(shí)現(xiàn)中看看Spring 是怎么做的:

/**
     * Create new XmlBeanDefinitionReader for the given bean factory.
     * @param registry the BeanFactory to load bean definitions into,
     * in the form of a BeanDefinitionRegistry
     */
    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);
    }


protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;

        // Determine ResourceLoader to use.
        if (this.registry instanceof ResourceLoader) {
            this.resourceLoader = (ResourceLoader) this.registry;
        }
        else {
            this.resourceLoader = new PathMatchingResourcePatternResolver();
        }

        // Inherit Environment if possible
        if (this.registry instanceof EnvironmentCapable) {
            this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
        }
        else {
            this.environment = new StandardEnvironment();
        }
    }

在實(shí)例化XmlBeanDefinitionReader 的過(guò)程中,在構(gòu)造函數(shù)中調(diào)用了其超類的構(gòu)造函數(shù),而在超類中對(duì)其所處換環(huán)境進(jìn)行的判斷,所謂的環(huán)境呢,事實(shí)上指得就是是通過(guò)BeanFactory, 還是通過(guò)ApplicationContext加載的上下文,這也就意味著不同方式加載可能存在某些不同。寫這些的目的其實(shí)是為了引出這里的一個(gè)我們十分關(guān)注的東西, 就是自動(dòng)裝配。在AbstractAutowireCapableBeanFactory這個(gè)抽象類的構(gòu)造方法中實(shí)現(xiàn)了相關(guān)的自動(dòng)裝配,在BeanDefinitionRegistry 和DefaultListableBeanFactory中都繼承了這個(gè)抽象類, 并在其構(gòu)造函數(shù)內(nèi)直接調(diào)用了其超類的構(gòu)造函數(shù)也就是:

/**
     * Create a new AbstractAutowireCapableBeanFactory.
     */
    public AbstractAutowireCapableBeanFactory() {
        super();
        ignoreDependencyInterface(BeanNameAware.class);
        ignoreDependencyInterface(BeanFactoryAware.class);
        ignoreDependencyInterface(BeanClassLoaderAware.class);
    }
這里有必要提及一下ignoreDependencyInterface();這個(gè)方法。它的主要功能就是忽略接口中的自動(dòng)裝配, 那么這樣做的目的是什么呢?會(huì)產(chǎn)生什么樣的效果呢?舉例來(lái)說(shuō), 當(dāng)A中有屬性B, 那么Spring在獲取A的時(shí)候就會(huì)去先去獲取B, 然而有些時(shí)候Spring不會(huì)這樣做,就是Spring通過(guò)BeanNameAware、BeanFactoryAware和BeanClassLoaderAware進(jìn)行注入的, 也就是根據(jù)環(huán)境的不同, Spring會(huì)選擇相應(yīng)的自從裝配的方式。在不是當(dāng)前環(huán)境中的注入,Spring并不會(huì)再當(dāng)前環(huán)境對(duì)Bean進(jìn)行自動(dòng)裝配。類似于,BeanFactory通過(guò)BeanFactoryAwar進(jìn)行注入或者ApplicationContext通過(guò)ApplicationContextAware進(jìn)行注入。

經(jīng)過(guò)了這么長(zhǎng)時(shí)間的鋪墊,終于應(yīng)該進(jìn)入正題了, 就是進(jìn)入通過(guò)loadBeanDefinitions(resource)方法加載這個(gè)文件。這個(gè)方法這樣實(shí)現(xiàn):

 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isTraceEnabled()) {
            logger.trace("Loading XML bean definitions from " + encodedResource);
        }

        Set currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        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();
            }
        }
    }

這段代碼很容易理解,不過(guò)真正實(shí)現(xiàn)的核心代碼是在return doLoadBeanDefinitions(inputSource, encodedResource.getResource());這里實(shí)現(xiàn)的。下面是這個(gè)方法的核心代碼:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {

        try {
            Document doc = doLoadDocument(inputSource, resource);
            int count = registerBeanDefinitions(doc, resource);
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            return count;
        }
}

這段處理可以說(shuō)非常容易了,對(duì)resource流進(jìn)行再封裝,封裝為Docment對(duì)象,然后解析并注冊(cè)這個(gè)doc中的bean對(duì)象,返回定義的bean的個(gè)數(shù)。在Spring3.1之前上面這個(gè)方法中還要驗(yàn)證加載Xml是否符合規(guī)范。而Spring5.x之后Spring將驗(yàn)證的工作放到了獲取Document中。

三、獲取Document

看一下Document doc = doLoadDocument(inputSource, resource);這個(gè)方法的源碼:


protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
                getValidationModeForResource(resource), isNamespaceAware());
    }

在這個(gè)方法中做了三件事:

getEntityResolver();這個(gè)方法將根據(jù)當(dāng)前的resource創(chuàng)建一個(gè)ResourceLoader實(shí)例,然后根據(jù)這個(gè)對(duì)ResourceLoader進(jìn)行封裝,封裝為EntityResolver實(shí)例, 這個(gè)EntityResolver的作用是進(jìn)行處理實(shí)體映射。

getValidationModeForResource(); 這個(gè)方法的作用是獲取資源的驗(yàn)證模式,通過(guò)自動(dòng)或手動(dòng)的方式對(duì)已經(jīng)加載到的資源進(jìn)行檢驗(yàn)。這里是真正對(duì)xml文件進(jìn)行驗(yàn)證的地方。

isNamespaceAware(); 這個(gè)方法用來(lái)判斷加載的xml文件是否支持明明空間。

實(shí)現(xiàn)上面方法的類繼承了這個(gè)接口:DocumentLoader,并且實(shí)現(xiàn)了這個(gè)接口中的唯一的抽象:

/**
 * Load a {@link Document document} from the supplied {@link InputSource source}.
 * @param inputSource the source of the document that is to be loaded
 * @param entityResolver the resolver that is to be used to resolve any entities
 * @param errorHandler used to report any errors during document loading
 * @param validationMode the type of validation
 * {@link org.springframework.util.xml.XmlValidationModeDetector#VALIDATION_DTD DTD}
 * or {@link org.springframework.util.xml.XmlValidationModeDetector#VALIDATION_XSD XSD})
 * @param namespaceAware {@code true} if support for XML namespaces is to be provided
 * @return the loaded {@link Document document}
 * @throws Exception if an error occurs
 */

Document loadDocument(

    InputSource inputSource, EntityResolver entityResolver,
    ErrorHandler errorHandler, int validationMode, boolean namespaceAware)
    throws Exception;

那么詳細(xì)講一下上面提及的EntityResolver, 如果SAX(Simple API for XML:簡(jiǎn)單的來(lái)講,它的作用就是不去構(gòu)建DOM,而是以應(yīng)用程序的方式以最有效率的方式實(shí)現(xiàn)XML與應(yīng)用實(shí)體之間的映射;當(dāng)然還有一種方式是解析DOM,具體兩種方式,我也沒有做過(guò)相應(yīng)深入探究)應(yīng)用驅(qū)動(dòng)程序需要實(shí)現(xiàn)自定義的處理外部實(shí)體,在必須實(shí)現(xiàn)此接口并通過(guò)某種方式向SAX驅(qū)動(dòng)器注冊(cè)一個(gè)實(shí)例。這需要根據(jù)XML頭部的DTD中的網(wǎng)絡(luò)地址下載聲明并認(rèn)證,而EntityResolver實(shí)際上就是在提供一個(gè)尋dtd找聲明的方法,這樣就可以在項(xiàng)目中直接定義好聲明,而通過(guò)本地尋找的方式避免了網(wǎng)絡(luò)尋找的過(guò)程,編譯器也避免了在網(wǎng)絡(luò)延遲高或沒有網(wǎng)絡(luò)的情況下報(bào)錯(cuò)。

四、解析及注冊(cè)BeanDefinitions
當(dāng)文件轉(zhuǎn)換為Document后,接下來(lái)提取及注冊(cè)Bean就是我們后頭的重頭戲。事實(shí)上,這一部分內(nèi)容并不會(huì)在我們的使用中出現(xiàn)了。

同樣在XmlBeanDefinitionReader這個(gè)類中,可以發(fā)現(xiàn)隨著Docment的獲取完成后,直接做的是下面的這個(gè)事情registerBeanDefinitions();

/**
 * Register the bean definitions contained in the given DOM document.
 * Called by {@code loadBeanDefinitions}.
 * 

Creates a new instance of the parser class and invokes * {@code registerBeanDefinitions} on it. * @param doc the DOM document * @param resource the resource descriptor (for context information) * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of parsing errors * @see #loadBeanDefinitions * @see #setDocumentReaderClass * @see BeanDefinitionDocumentReader#registerBeanDefinitions */ public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }

作用在注釋中寫的很清楚,注冊(cè)DOM文檔(Spring的配置信息中. 也就是解析后的xml)中包含的bean。

首先創(chuàng)建一個(gè)bean定義文檔讀取器,這個(gè)對(duì)象是根據(jù)DefaultBeanDefinitionDocumentReader的class通過(guò)反射的方式來(lái)創(chuàng)建的,

DefaultBeanDefinitionDocumentReader實(shí)現(xiàn)了BeanDefinitionDocumentReader這個(gè)接口,這里唯一的抽象方法就是registerBeanDefinitions(Document doc, XmlReaderContext readerContext);,這也就意味著上面的第三行代碼是一個(gè)自然的應(yīng)用。

提示:這里的doc參數(shù)就是通過(guò)之前的doLoadDocument方法獲得的,而這很好的應(yīng)用了面向?qū)ο蟮膯我宦氊?zé)原則, 將轉(zhuǎn)換為Docment的復(fù)雜過(guò)程交給一個(gè)單一的類處理,而這個(gè)類就是BeanDefinitionDocumentReader, 事實(shí)上這是一個(gè)接口,而具體的實(shí)例化是在createBeanDefinitionDocumentReader這個(gè)方法中完成的。

getRegistry();的作用實(shí)際上是獲得一個(gè)BeanDefinitionRegistry對(duì)象。下面的圖片是程序最開始時(shí),容器開始實(shí)現(xiàn)時(shí)候的代碼,這里可以看到BeanDefinitionRegistry這個(gè)接口。注意這里創(chuàng)建的BeanDefinitionRegistry是final的,也就是這里獲取的是Spring發(fā)現(xiàn)的所有的bean個(gè)數(shù),是不許改變的, 熟悉設(shè)計(jì)模式的同學(xué)肯定知道,這個(gè)BeanDefinitionRegistry是一個(gè)單例的

而接下來(lái)做的就是就是,記錄所有對(duì)我們的資源文件進(jìn)行加載,這里是真正解析xml文件并加載的地方,而這個(gè)邏輯就是那么簡(jiǎn)單了, 先統(tǒng)計(jì)當(dāng)前的bean defintions個(gè)數(shù)然后加載一些bean定義進(jìn)來(lái),然后在統(tǒng)計(jì)bean 的個(gè)數(shù),然后用后來(lái)的減去開始的就是加載的。沒錯(cuò)了,就是學(xué)前班加減法。

到這里我已經(jīng)不想探究xml文件是如何讀取的了,如果想看的話,可以去看下一篇《Spring源碼一(容器的基本實(shí)現(xiàn)2)》!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/72023.html

相關(guān)文章

  • Spring IOC 容器源碼分析系列文章導(dǎo)讀

    摘要:本文是容器源碼分析系列文章的第一篇文章,將會(huì)著重介紹的一些使用方法和特性,為后續(xù)的源碼分析文章做鋪墊。我們可以通過(guò)這兩個(gè)別名獲取到這個(gè)實(shí)例,比如下面的測(cè)試代碼測(cè)試結(jié)果如下本小節(jié),我們來(lái)了解一下這個(gè)特性。 1. 簡(jiǎn)介 Spring 是一個(gè)輕量級(jí)的企業(yè)級(jí)應(yīng)用開發(fā)框架,于 2004 年由 Rod Johnson 發(fā)布了 1.0 版本。經(jīng)過(guò)十幾年的迭代,現(xiàn)在的 Spring 框架已經(jīng)非常成熟了...

    NSFish 評(píng)論0 收藏0
  • Spring源碼容器基本實(shí)現(xiàn)2)

    摘要:進(jìn)一步解析其他所有屬性并統(tǒng)一封裝至類型的實(shí)例中。是一個(gè)接口,在中存在三種實(shí)現(xiàn)以及。通過(guò)將配置文件中配置信息轉(zhuǎn)換為容器的內(nèi)部表示,并將這些注冊(cè)到中。容器的就像是配置信息的內(nèi)存數(shù)據(jù)庫(kù),主要是以的形式保存。而代碼的作用就是實(shí)現(xiàn)此功能。 前言:繼續(xù)前一章。 一、porfile 屬性的使用 如果你使用過(guò)SpringBoot, 你一定會(huì)知道porfile配置所帶來(lái)的方便, 通過(guò)配置開發(fā)環(huán)境還是生產(chǎn)...

    yagami 評(píng)論0 收藏0
  • Java深入-框架技巧

    摘要:從使用到原理學(xué)習(xí)線程池關(guān)于線程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實(shí)現(xiàn)在軟件開發(fā)中,分散于應(yīng)用中多出的功能被稱為橫切關(guān)注點(diǎn)如事務(wù)安全緩存等。 Java 程序媛手把手教你設(shè)計(jì)模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經(jīng)風(fēng)雨慢慢變老,回首走過(guò)的點(diǎn)點(diǎn)滴滴,依然清楚的記得當(dāng)初愛情萌芽的模樣…… Java 進(jìn)階面試問(wèn)題列表 -...

    chengtao1633 評(píng)論0 收藏0
  • 起來(lái)讀Spring源碼吧(容器初始化

    摘要:對(duì)于開發(fā)者來(lái)說(shuō),無(wú)疑是最常用也是最基礎(chǔ)的框架之一。概念上的東西還是要提一嘴的用容器來(lái)管理。和是容器的兩種表現(xiàn)形式。定義了簡(jiǎn)單容器的基本功能。抽象出一個(gè)資源類來(lái)表示資源調(diào)用了忽略指定接口的自動(dòng)裝配功能委托解析資源。 對(duì)于Java開發(fā)者來(lái)說(shuō),Spring無(wú)疑是最常用也是最基礎(chǔ)的框架之一。(此處省略1w字吹Spring)。相信很多同行跟我一樣,只是停留在會(huì)用的階段,比如用@Component...

    libxd 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<