1. 程式人生 > >Spring Ioc 的源碼初識

Spring Ioc 的源碼初識

圖片 turn add 構造方法 tel exception 加載 ioc ann

剛學習Spring的時候,印象最深的就是 DispatcherServlet,所謂的中央調度器,我也嘗試從這個萬能膠這裏找到入口

技術分享圖片

configureAndRefreshWebApplicationContext()方法,應該就是IOC容器初始化的真正入口

我開始手寫測試用例(xml配置的bean實例),ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("xxx.xml");

通過跟蹤代碼和debug的方式,找到了大概的初始化流程

ClassPathXmlApplicationContext 的構造方法

    public ClassPathXmlApplicationContext(String configLocation) 
   throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

技術分享圖片

AbstractApplicationContext類

技術分享圖片

接著--->>>

技術分享圖片

接著--->>>AbstractXmlApplicationContext

        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        //創建XmlBeanDefinitionReader
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        beanDefinitionReader.setEnvironment(
this.getEnvironment()); //容器本身也是一個資源加載器 beanDefinitionReader.setResourceLoader(this); //為Bean讀取器設置SAX xml解析器 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //當Bean讀取器讀取Bean定義的Xml資源文件時,啟用Xml的校驗機制 initBeanDefinitionReader(beanDefinitionReader); //Bean讀取器真正實現加載的方法 loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //獲取Bean定義資源的定位 Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } //如果子類中獲取的Bean定義資源定位為空,則獲取FileSystemXmlApplicationContext構造方法中setConfigLocations方法設置的資源 String[] configLocations = getConfigLocations(); if (configLocations != null) { //Xml Bean讀取器調用其父類AbstractBeanDefinitionReader讀取定位 reader.loadBeanDefinitions(configLocations); } }

接著--->>>AbstractBeanDefinitionReader

    public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        Assert.notNull(locations, "Location array must not be null");
        int counter = 0;
        for (String location : locations) {
            counter += loadBeanDefinitions(location);
        }
        return counter;
           }

接著--->>>

public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { return loadBeanDefinitions(location, null); }

接著--->>>

    public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        //獲取在IoC容器初始化過程中設置的資源加載器
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        }

        if (resourceLoader instanceof ResourcePatternResolver) {
            try {
                //加載多個指定位置的Bean定義資源文件
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                //委派調用其子類XmlBeanDefinitionReader的方法,實現加載功能
                int loadCount = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    for (Resource resource : resources) {
                        actualResources.add(resource);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                }
                return loadCount;
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(
                        "Could not resolve bean definition resource pattern [" + location + "]", ex);
            }
        }
        else {
            Resource resource = resourceLoader.getResource(location);
            int loadCount = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
            }
            return loadCount;
        }
          }

接著--->>>

       public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int counter = 0;
        for (Resource resource : resources) {
            counter += loadBeanDefinitions(resource);
        }
        return counter;
           }

接著--->>>XmlBeanDefinitionReader

      public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        //將讀入的XML資源進行特殊編碼處理
        return loadBeanDefinitions(new EncodedResource(resource));
           }

接著--->>>

    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isInfoEnabled()) {logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }
        Set<EncodedResource> 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的IO流
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                //從InputStream中得到XML的解析源
                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();
            }
        }
           }

接著--->>>

       protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            //將XML文件轉換為DOM對象,解析過程由documentLoader實現
            Document doc = doLoadDocument(inputSource, resource);
            //這裏是啟動對Bean定義解析的詳細過程,該解析過程會用到Spring的Bean配置規則
            return registerBeanDefinitions(doc, resource);
        }
        catch (Exception ex) {
            throw ex;
        }}

接著--->>>

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //獲取BeanDefinitionDocumentReader
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        //獲得容器中註冊的Bean數量
        int countBefore = getRegistry().getBeanDefinitionCount();
        //具體的解析實現過程實現類DefaultBeanDefinitionDocumentReader完成
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        //統計解析的Bean數量
        return getRegistry().getBeanDefinitionCount() - countBefore;
            }

接著--->>>DefaultBeanDefinitionDocumentReader

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        //獲得XML描述符
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
        //獲得Document的根元素
        Element root = doc.getDocumentElement();
        doRegisterBeanDefinitions(root);
            }

接著--->>>

        protected void doRegisterBeanDefinitions(Element root) {
        //具體的解析過程由BeanDefinitionParserDelegate實現,
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);
        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isInfoEnabled()) {logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }return;}}}
        //在解析Bean定義之前,進行自定義的解析,增強解析過程的可擴展性
        preProcessXml(root);
        //從Document的根元素開始進行Bean定義的Document對象
        parseBeanDefinitions(root, this.delegate);
        //在解析Bean定義之後,進行自定義的解析,增加解析過程的可擴展性
        postProcessXml(root);
        this.delegate = parent;
    }

接著--->>>

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //Bean定義的Document對象使用了Spring默認的XML命名空間
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                //獲得Document節點是XML元素節點
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    //Bean定義的Document的元素節點使用的是Spring默認的XML命名空間
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
          }

接著--->>>

          private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        //如果元素節點是<Import>導入元素,進行導入解析
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        //如果元素節點是<Alias>別名元素,進行別名解析
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        //按照Spring的Bean規則解析元素
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
        }
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
            doRegisterBeanDefinitions(ele);
        }
            }

接著--->>>

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        // BeanDefinitionHolder是對BeanDefinition的封裝,即Bean定義的封裝類
        // BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                //向Spring IOC容器註冊解析得到的Bean定義,這是Bean定義向IOC容器註冊的入口
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name ‘" +bdHolder.getBeanName() + "‘", ele, ex);
            }
            //在完成向Spring IOC容器註冊解析得到的Bean定義之後,發送註冊事件
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
             }

接著--->>>BeanDefinitionReaderUtils

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {
        //獲取解析的BeanDefinition的名稱
        String beanName = definitionHolder.getBeanName();
        //向IOC容器註冊BeanDefinition
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        //如果解析的BeanDefinition有別名,向容器為其註冊別名
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
           }

Spring Ioc 的源碼初識