首頁  >  文章  >  Java  >  Spring-IOC容器的介紹(附程式碼)

Spring-IOC容器的介紹(附程式碼)

不言
不言轉載
2019-03-27 10:42:122302瀏覽

這篇文章帶給大家的內容是關於Spring-IOC容器的介紹(附程式碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

Spring IoC容器對Bean定義資源的載入是從refresh()函數開始的,refresh()是一個模板方法,refresh()方法的作用是:在建立IoC容器前,如果已經有容器存在,則需要把已有的容器銷毀並關閉,以確保在refresh之後使用的是新建立起來的IoC容器。 refresh的作用類似於IoC容器的重啟,在新建立好的容器中對容器進行初始化,對Bean定義資源進行載入

public void refresh() throws BeansException, IllegalStateException {
       Object var1 = this.startupShutdownMonitor;
       synchronized(this.startupShutdownMonitor) {
           //调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
           this.prepareRefresh();
           //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从  
           //子类的refreshBeanFactory()方法启动 
           //这个bean的载入过程 包括对xml的解析和加载为BeanDefinitions 都是从this.obtainFreshBeanFactory()这里进入
           ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
           /*这之后的代码都是注册容器的信息源和生命周期事件*/
           //为BeanFactory配置容器特性,例如类加载器、事件处理器等
           this.prepareBeanFactory(beanFactory);

           try {
               //为容器的某些子类指定特殊的BeanPost事件处理器
               this.postProcessBeanFactory(beanFactory);
               //调用所有注册的BeanFactoryPostProcessor的Bean
               this.invokeBeanFactoryPostProcessors(beanFactory);
               //为BeanFactory注册BeanPost事件处理器.  
               //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件 
               this.registerBeanPostProcessors(beanFactory);
               //初始化信息源,和国际化相关.
               this.initMessageSource();
               //初始化容器事件传播器.
               this.initApplicationEventMulticaster();
               //调用子类的某些特殊Bean初始化方法
               this.onRefresh();
               //为事件传播器注册事件监听器. 
               this.registerListeners();
               //初始化所有剩余的单态Bean.
               this.finishBeanFactoryInitialization(beanFactory);
               //初始化容器的生命周期事件处理器,并发布容器的生命周期事件
               this.finishRefresh();
           } catch (BeansException var9) {
               if (this.logger.isWarnEnabled()) {
                   this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
               }
               //销毁以创建的单态Bean
               this.destroyBeans();
               //取消refresh操作,重置容器的同步标识.
               this.cancelRefresh(var9);
               throw var9;
           } finally {
               this.resetCommonCaches();
           }

       }
   }

AbstractRefreshableApplicationContext 類別:
AbstractRefreshableApplicationContext中只定義了抽象的loadBeanDefinitions方法,容器真正呼叫的是其子類別AbstractXmlApplicationContext對此方法的實作

protected final void refreshBeanFactory() throws BeansException {
        //如果已经创建了BeanFactory,则销毁并关闭BeanFactory
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
             //创建了一个IOC容器
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            /对IoC容器进行定制化,如设置启动参数,开启注解的自动装配等
            this.customizeBeanFactory(beanFactory);
            //调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
            this.loadBeanDefinitions(beanFactory);
            Object var2 = this.beanFactoryMonitor;
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

AbstractXmlApplicationContext 類別:

 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        //创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源  
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
         //为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的  
        //祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器
        beanDefinitionReader.setResourceLoader(this);
        //为Bean读取器设置SAX xml解析器 
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        //当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制  
        this.initBeanDefinitionReader(beanDefinitionReader);
        //Bean读取器真正实现加载的方法
        this.loadBeanDefinitions(beanDefinitionReader);
    }
    
    protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
        reader.setValidating(this.validating);
    }

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = this.getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }

        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }

    }

    @Nullable
    protected Resource[] getConfigResources() {
        return null;
    }

在其抽象父類AbstractBeanDefinitionReader#rr

具體載入資源的方法

首先,呼叫資源載入器的取得資源方法resourceLoader.getResource(location),取得到要載入的資源。
其次,真正執行載入功能是其子類別XmlBeanDefinitionReader的loadBeanDefinitions方法。
資源定位到這裡就結束 最終回傳的是一個Resource的物件來進行BeanDefinition的載入。在定位完成後,為BeanDefinition的載入創客I/O條件,
但是具體的載入還沒有開始載入。

 public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        //获取resourceLoader
        ResourceLoader resourceLoader = this.getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        } else {
            int loadCount;
            if (!(resourceLoader instanceof ResourcePatternResolver)) {
                //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源  
                //加载多个指定位置的Bean定义资源文件 完成具体的资源定位的工作               
                Resource resource = resourceLoader.getResource(location);
                //加载资源 开始我们的第二步操作 转换为BeanDefinition对象
                loadCount = this.loadBeanDefinitions((Resource)resource);
                if (actualResources != null) {
                    actualResources.add(resource);
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
                }

                return loadCount;
            } else {
                try {
                   //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源  
                   //加载单个指定位置的Bean定义资源文件  
                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
                    //加载资源 开始我们的第二步操作 转换为BeanDefinition对象
                    loadCount = this.loadBeanDefinitions(resources);
                    if (actualResources != null) {
                        Resource[] var6 = resources;
                        int var7 = resources.length;

                        for(int var8 = 0; var8 < var7; ++var8) {
                            Resource resource = var6[var8];
                            actualResources.add(resource);
                        }
                    }

                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                    }

                    return loadCount;
                } catch (IOException var10) {
                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
                }
            }
        }
    }
public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");
        Iterator var2 = this.protocolResolvers.iterator();

        Resource resource;
        do {
            if (!var2.hasNext()) {
               //处理/开头的定位
                if (location.startsWith("/")) {
                    return this.getResourceByPath(location);
                }
                //带有classpath标识的Resource
                if (location.startsWith("classpath:")) {
                    return new ClassPathResource(location.substring("classpath:".length()), this.getClassLoader());
                }

                try {
                //处理URL标识的Resource定位
                    URL url = new URL(location);
                    return (Resource)(ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
                } catch (MalformedURLException var5) {
                    //如果不存classpath、Url、/标志的 就教给他处理
                    return this.getResourceByPath(location);
                }
            }

            ProtocolResolver protocolResolver = (ProtocolResolver)var2.next();
            resource = protocolResolver.resolve(location, this);
        } while(resource == null);

        return resource;
    }
BeanDefinition的載入分成兩部分,首先透過XML的解析器得到document對象,

但這些document物件沒有依照spring的Bean規則進行解析。在完成XML解析後,才是依照Spring的Bean規則來解析,這個解析的過程是在documentReader實作。

protected Resource getResourceByPath(String path) {    
   if (path != null && path.startsWith("/")) {    
        path = path.substring(1);    
    }  
    //这里使用文件系统资源对象来定义bean 文件
    return new FileSystemResource(path);  
}
xml檔案轉換為document物件再解析BeanDefinition

這裡是載入XML形式Bean定義資源檔案方法

 public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        //获取resourceLoader
        ResourceLoader resourceLoader = this.getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        } else {
            int loadCount;
            if (!(resourceLoader instanceof ResourcePatternResolver)) {
                //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源  
                //加载多个指定位置的Bean定义资源文件 完成具体的资源定位的工作               
                Resource resource = resourceLoader.getResource(location);
 
                //加载资源 开始我们的第二步操作 转换为BeanDefinition对象
                loadCount = this.loadBeanDefinitions((Resource)resource);
                if (actualResources != null) {
                    actualResources.add(resource);
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
                }

                return loadCount;
            } else {
                try {
                   //将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源  
                   //加载单个指定位置的Bean定义资源文件  
                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
                    //加载资源 开始我们的第二步操作 转换为BeanDefinition对象
                    loadCount = this.loadBeanDefinitions(resources);
                    if (actualResources != null) {
                        Resource[] var6 = resources;
                        int var7 = resources.length;

                        for(int var8 = 0; var8 < var7; ++var8) {
                            Resource resource = var6[var8];
                            actualResources.add(resource);
                        }
                    }

                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                    }

                    return loadCount;
                } catch (IOException var10) {
                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
                }
            }
        }
    }
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if(this.logger.isInfoEnabled()) {
            this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if(currentResources == null) {
            currentResources = new HashSet(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }

        if(!((Set)currentResources).add(encodedResource)) {
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
            int var5;
            try {
                //将资源文件转为InputStream的IO流
                InputStream inputStream = encodedResource.getResource().getInputStream();

                try {
                    //从InputStream中得到XML的解析源
                    InputSource inputSource = new InputSource(inputStream);
                    if(encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                     //这里是具体的读取过程
                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } finally {
                    //IO流的关闭
                    inputStream.close();
                }
            } catch (IOException var15) {
                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
            } finally {
                ((Set)currentResources).remove(encodedResource);
                if(((Set)currentResources).isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.remove();
                }

            }

            return var5;
        }
    }
@1

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
            //@1将XML文件转换为DOM对象,解析过程由documentLoader实现
            Document doc = this.doLoadDocument(inputSource, resource);
            //@2这里是启动对Bean定义解析的详细过程,该解析过程会用到Spring的Bean配置规则
            return this.registerBeanDefinitions(doc, resource);
        } catch (BeanDefinitionStoreException var4) {
            throw var4;
        } catch (SAXParseException var5) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
        } catch (SAXException var6) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
        } catch (ParserConfigurationException var7) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
        } catch (IOException var8) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
        } catch (Throwable var9) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
        }
    }
Spring IoC容器根據定位的Bean定義資源文件,將其載入讀入並轉換成為Document物件過程完成。

下面是Spring IoC容器將載入的Bean定義資源檔案轉換為Document物件之後,是如何將其解析為Spring IoC管理的Bean物件並將其註冊到容器中的

@2

//使用标准的JAXP将载入的Bean定义资源转换成document对象
 public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
        //创建文件解析器工厂 
        DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware);
        if(logger.isDebugEnabled()) {
            logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        //创建文档解析器  
        DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler);
        //解析Spring的Bean定义资源
        return builder.parse(inputSource);
    }

    protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware) throws ParserConfigurationException {
     //创建文档解析工厂
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(namespaceAware);
        if(validationMode != 0) {
           //设置解析XML的校验 
            factory.setValidating(true);
            if(validationMode == 3) {
                factory.setNamespaceAware(true);

                try {
                    factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
                } catch (IllegalArgumentException var6) {
                    ParserConfigurationException pcex = new ParserConfigurationException("Unable to validate using XSD: Your JAXP provider [" + factory + "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
                    pcex.initCause(var6);
                    throw pcex;
                }
            }
        }

        return factory;
    }
DefaultBeanDefinitionDocumentReader 解析document物件依照spring Bean的定義規則轉換為BeanDefinition

@1

 //按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构
 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        /得到BeanDefinitionDocumentReader来对xml格式的BeanDefinition解析 
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
        //获得容器中注册的Bean数量
        int countBefore = this.getRegistry().getBeanDefinitionCount();
        //解析过程入口,这里使用了委派模式,BeanDefinitionDocumentReader只是个接口
        //具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成
        //@1
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
        /统计解析的Bean数量 
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }
    //创建BeanDefinitionDocumentReader对象,解析Document对象
    protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
        return (BeanDefinitionDocumentReader)BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
    }
透過上述Spring IoC容器對載入的Bean定義Document解析可以看出,我們使用Spring時,在Spring設定檔中可以使用元素來導入IoC容器所需的其他資源,Spring IoC容器在解析時會先將指定導入的資源載入進容器中。使用別名時,Spring IoC容器首先將別名元素所定義的別名註冊到容器中。

對於既不是元素,又不是元素的元素,即Spring設定檔中普通的元素的解析由BeanDefinitionParserDelegate類別的parseBeanDefinitionElement方法來實作。

下面是針對對Bean元素的解析過程

 public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
    public static final String BEAN_ELEMENT = "bean";
    public static final String NESTED_BEANS_ELEMENT = "beans";
    public static final String ALIAS_ELEMENT = "alias";
    public static final String NAME_ATTRIBUTE = "name";
    public static final String ALIAS_ATTRIBUTE = "alias";
    public static final String IMPORT_ELEMENT = "import";
    public static final String RESOURCE_ATTRIBUTE = "resource";
    public static final String PROFILE_ATTRIBUTE = "profile";
    protected final Log logger = LogFactory.getLog(this.getClass());
    private XmlReaderContext readerContext;
    private BeanDefinitionParserDelegate delegate;

    public DefaultBeanDefinitionDocumentReader() {
    }
    //根据Spring DTD对Bean的定义规则解析Bean定义Document对象 
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        //获得XML描述符 
        this.readerContext = readerContext;
        this.logger.debug("Loading bean definitions");
        //获得Document的根元素 
        Element root = doc.getDocumentElement();
        this.doRegisterBeanDefinitions(root);
    }

    protected final XmlReaderContext getReaderContext() {
        return this.readerContext;
    }

    protected Object extractSource(Element ele) {
        return this.getReaderContext().extractSource(ele);
    }
    //具体的解析过程由BeanDefinitionParserDelegate实现,  
    //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素
    protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
        if(this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute("profile");
            if(StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
                if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if(this.logger.isInfoEnabled()) {
                        this.logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
                    }

                    return;
                }
            }
        }
        //在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
        this.preProcessXml(root);
        //从Document的根元素开始进行Bean定义的Document对象
        this.parseBeanDefinitions(root, this.delegate);
        //在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
        this.postProcessXml(root);
        this.delegate = parent;
    }
    //创建BeanDefinitionParserDelegate,用于完成真正的解析过程
    protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
        BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
        //BeanDefinitionParserDelegate初始化Document根元素
        delegate.initDefaults(root, parentDelegate);
        return delegate;
    }
    //使用Spring的Bean规则从Document的根元素开始进行Bean定义的Document对象
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
         //Bean定义的Document对象使用了Spring默认的XML命名空间
        if(delegate.isDefaultNamespace(root)) {
           //获取Bean定义的Document对象根元素的所有子节点
            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)) {
                        //使用Spring的Bean规则解析元素节点
                        this.parseDefaultElement(ele, delegate);
                    } else {
                       //没有使用Spring默认的XML命名空间,则使用用户自定义的解//析规则解析元素节点
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            //Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的  
           //解析规则解析Document根节点
            delegate.parseCustomElement(root);
        }

    }

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        //如果元素节点是<Import>导入元素,进行导入解析  
        if(delegate.nodeNameEquals(ele, "import")) {
            this.importBeanDefinitionResource(ele);
            
        } else if(delegate.nodeNameEquals(ele, "alias")) {
        //如果元素节点是<Alias>别名元素,进行别名解析 
            this.processAliasRegistration(ele);
        } else if(delegate.nodeNameEquals(ele, "bean")) {
        //元素节点既不是导入元素,也不是别名元素,即普通的<Bean>元素,  
        //按照Spring的Bean规则解析元素  
            this.processBeanDefinition(ele, delegate);
        } else if(delegate.nodeNameEquals(ele, "beans")) {
         //如果元素节点是<beans>元素注册为BeanDefintion
            this.doRegisterBeanDefinitions(ele);
        }

    }
    //解析<Import>导入元素,从给定的导入路径加载Bean定义资源到Spring IoC容器中
    protected void importBeanDefinitionResource(Element ele) {
        /获取给定的导入元素的location属性 
        String location = ele.getAttribute("resource");
        if(!StringUtils.hasText(location)) {
            this.getReaderContext().error("Resource location must not be empty", ele);
        } else {
            //获取location的值 
            location = this.getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
            Set<Resource> actualResources = new LinkedHashSet(4);
            //标识给定的导入元素的location是否是绝对路径
            boolean absoluteLocation = false;

            try {
                absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
            } catch (URISyntaxException var11) {
                ;
            }

            int importCount;
            if(absoluteLocation) {
                try {
                    //使用资源读入器加载给定路径的Bean定义资源
                    importCount = this.getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
                    }
                } catch (BeanDefinitionStoreException var10) {
                    this.getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, var10);
                }
            } else {
            //给定的导入元素的location是相对路径  
                try {
                    Resource relativeResource = this.getReaderContext().getResource().createRelative(location);
                    if(relativeResource.exists()) {
                         //使用资源读入器加载Bean定义资源 
                        importCount = this.getReaderContext().getReader().loadBeanDefinitions(relativeResource);
                        actualResources.add(relativeResource);
                    } else {
                        String baseLocation = this.getReaderContext().getResource().getURL().toString();
                        importCount = this.getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources);
                    }

                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
                    }
                } catch (IOException var8) {
                    this.getReaderContext().error("Failed to resolve current resource location", ele, var8);
                } catch (BeanDefinitionStoreException var9) {
                    this.getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, var9);
                }
            }
            //在解析完<Import>元素之后,发送容器导入其他资源处理完成事件
            Resource[] actResArray = (Resource[])actualResources.toArray(new Resource[actualResources.size()]);
            this.getReaderContext().fireImportProcessed(location, actResArray, this.extractSource(ele));
        }
    }
   //解析<Alias>别名元素,为Bean向Spring IoC容器注册别名  
    protected void processAliasRegistration(Element ele) {
        //获取<Alias>别名元素中name的属性值
        String name = ele.getAttribute("name");
        //获取<Alias>别名元素中alias的属性值  
        String alias = ele.getAttribute("alias");
        boolean valid = true;
        if(!StringUtils.hasText(name)) {
            this.getReaderContext().error("Name must not be empty", ele);
            valid = false;
        }

        if(!StringUtils.hasText(alias)) {
            this.getReaderContext().error("Alias must not be empty", ele);
            valid = false;
        }

        if(valid) {
            try {
                //向容器的资源读入器注册别名
                this.getReaderContext().getRegistry().registerAlias(name, alias);
            } catch (Exception var6) {
                this.getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, var6);
            }
            //在解析完<Alias>元素之后,发送容器别名处理完成事件
            this.getReaderContext().fireAliasRegistered(name, alias, this.extractSource(ele));
        }

    } 
    //解析Bean定义资源Document对象的普通元素
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类  
       //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现  BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if(bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
                //向Spring IoC容器注册解析得到的Bean定义,这是Bean定义向IoC容器注册的入口
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }
            //在完成向Spring IoC容器注册解析得到的Bean定义之后,发送注册事件
            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }

    protected void preProcessXml(Element root) {
    }

    protected void postProcessXml(Element root) {
    }
}
透過對上述原始碼的分析,就會明白我們在Spring設定檔中元素的中配置的屬性就是透過該方法解析和設定到Bean中去的。

注意:在解析元素過程中沒有建立和實例化Bean對象,只是建立了Bean對象的定義類別BeanDefinition,將元素中的設定資訊設定到BeanDefinition中作為記錄,當依賴注入時才使用這些記錄資訊來建立和實例化具體的Bean物件。
上面方法中一些對一些配置如元資訊(meta)、qualifier等的解析,我們在Spring中配置時使用的也不多,我們在使用Spring的元素時,配置最多的是屬性。

呼叫BeanDefinitionReaderUtils的registerBeanDefinition方法向IoC容器註冊解析的Bean

    //解析Bean定义资源文件中的<Bean>元素,这个方法中主要处理<Bean>元素的id,name
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        //获取id属性
        String id = ele.getAttribute("id");
        //获取name属性
        String nameAttr = ele.getAttribute("name");
        List<String> aliases = new ArrayList();
        //将Bean元素的name属性全部放到alias属性里面
        if(StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        if(!StringUtils.hasText(id) && !aliases.isEmpty()) {
            beanName = (String)aliases.remove(0);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
            }
        }

        if(containingBean == null) {
            //检查bean元素的id和name是否是唯一的 
            this.checkNameUniqueness(beanName, aliases, ele);
        }
        //详细对<Bean>元素中配置的Bean定义进行解析的地方
        AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
        if(beanDefinition != null) {
            if(!StringUtils.hasText(beanName)) {
                try {
                    if(containingBean != null) {
                        //判断如果没有id和name属性时候是否包含子元素的<Bean>
                        beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                    } else {
                        //如果<Bean>元素中没有配置id、别名或者name,且包含了子//<Bean>元素,为解析的Bean使用别名向IoC容器注册  
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        String beanClassName = beanDefinition.getBeanClassName();
                        if(beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }

                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
                    }
                } catch (Exception var9) {
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }

            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }
    }
    //详细解析bean元素的地方
    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        String className = null;
        //是否包含class属性
        if(ele.hasAttribute("class")) {
            //获取class属性值 不做实例化,bean的实例化是在第一次获取bean的时候完成,这里只获取class的值
            className = ele.getAttribute("class").trim();
        }

        try {
            String parent = null;
            //如果<Bean>元素中配置了parent属性,则获取parent属性的值
            if(ele.hasAttribute("parent")) {
                parent = ele.getAttribute("parent");
            }
           //根据<Bean>元素配置的class名称和parent属性值创建BeanDefinition  
            //为载入Bean定义信息做准备 
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            //对当前的<Bean>元素中配置的一些属性进行解析和设置,如配置的单态(singleton)属性等
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            //为<Bean>元素解析的Bean设置description信息 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
            //对<Bean>元素的meta(元信息)属性解析
            this.parseMetaElements(ele, bd);
            //对<Bean>元素的lookup-method属性解析
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //对<Bean>元素的replaced-method属性解析
            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //解析<Bean>元素的构造方法设置
            this.parseConstructorArgElements(ele, bd);
             //解析<Bean>元素的<property>设置
            this.parsePropertyElements(ele, bd);
             //解析<Bean>元素的qualifier属性
            this.parseQualifierElements(ele, bd);
            bd.setResource(this.readerContext.getResource());
            bd.setSource(this.extractSource(ele));
            AbstractBeanDefinition var7 = bd;
            return var7;
        } catch (ClassNotFoundException var13) {
            this.error("Bean class [" + className + "] not found", ele, var13);
        } catch (NoClassDefFoundError var14) {
            this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
        } catch (Throwable var15) {
            this.error("Unexpected failure during bean definition parsing", ele, var15);
        } finally {
            this.parseState.pop();
        }

        return null;
    }
當呼叫BeanDefinitionReaderUtils向IoC容器註冊解析的BeanDefinition時,真正完成註冊功能的是DefaultListableBeanFactory。

 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if(bdHolder != null) {
            //通过对document对象的解析和封装返回一个BeanDefinitionHolder
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
                //通过这个holder来注册bean对象
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }

            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }
DefaultListableBeanFactory registerBeanDefinition方法

    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
        String[] aliases = definitionHolder.getAliases();
        if(aliases != null) {
            String[] var4 = aliases;
            int var5 = aliases.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String alias = var4[var6];
                registry.registerAlias(beanName, alias);
            }
        }

    }
至此,Bean定義資源檔案中配置的Bean被解析過後,已經註冊到IoC容器中,被容器管理起來,真正完成了IoC容器初始化所做的全部工作。現  在IoC容器中已經建立了整個Bean的配置信息,這些BeanDefinition信息已經可以使用,並且可以被檢索,IoC容器的作用就是對這些註冊的Bean定義信息進行處理和維護。這些的註冊的Bean定義資訊是IoC容器控制反轉的基礎,而正是有了這些註冊的數據,容器才可以進行依賴注入。

這篇文章到這裡就已經全部結束了,更多其他精彩內容可以關注PHP中文網的

Java影片教學專欄!

#

以上是Spring-IOC容器的介紹(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除