SpringIoC-容器初始化过程

IoC:依赖倒置原理,个人觉得其核心思想就是减少代码的耦合度,很多复杂的应用都是依靠多个类之间的合作来完成的。如果类本身和合作类的引用需要靠自身来实现,那么代码的耦合度会很高。那么在Spring中,IoC是实现依赖反转的载体;Spring在对象初始化的时候将数据注入到对象中,或者将对象的引用注入到数据域中的方式来注入对方法调用的依赖

Spring IoC提供了一个基本的javaBean容器,通过IoC模式管理依赖关系,并通过依赖注入和AOP切面增强了为javeBean这样的POJO对象赋予事务管理,生命周期管理等基本功能。而Bean都在Spring容器里,Spring容器负责它们的创建,装配,管理它们整个的生命周期。《深入理解Spring技术内幕》

SpringIoC容器系列(BeanFactory跟ApplicationContext)

BeanFactory跟ApplicationContext都属于Spring容器。
BeanFactory:定义了最基本的容器设计规范,如getBean(),containBean(),getType()等基本的方法。

ApplicationContext:由图可知ApplicationContext应用的上下文都是基于ConfigurableApplicationContext跟WebApplicationContext的实现。ApplicationContext继承了BeanFactory的接口同时又继承MessageSource(支持不同的信息源),ResourceLoader(访问资源),ApplicationEventPublisher(支持应用事件)。

IoC接口设计图

图片引用《深入理解spring技术内幕》

容器是如何初始化的?

容器的初始化是通过refresh()方法来完成的,总共包括三个步骤:

  • 定位:通过Resource定位BeanDefinition,BeanDefinition抽象了对bean的定义,比如bean的信息,依赖关系等。这个过程可以想象成寻找bean的过程。

下面我们通过代码来简要分析下容器是如何初始化的

public class ApplicationContextInit {

    public static void main(String[] args) {
        FileSystemXmlApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext("bean.xml");
    }
}

FileSystemXmlApplicationContext是通过文件来载入Resource的,运行上述代码

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
    //...省略部分源码
    //通过文件的位置来定位到beanDefinition
    public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }
    
    //通过refresh()方法来完成BeanDefinition信息读取和载入
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
    @Override
    protected Resource getResourceByPath(String path) {
        if (path != null && path.startsWith("/")) {
            path = path.substring(1);
        }
        return new FileSystemResource(path);
    }

}

refresh()来启动IoC容器的初始化

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 容器初始化的一些准备工作.
            prepareRefresh();

            // 告知子类要初始化BeanFactory,BeanDefinition信息的读取是在子类的
            // refreshBeanFactory()方法里完成的
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 准备bean工厂以在此上下文中使用。
            prepareBeanFactory(beanFactory);

            try {
                // 设置beanFactory的后置处理
                postProcessBeanFactory(beanFactory);
                // 调用beanFactory的后置处理
                invokeBeanFactoryPostProcessors(beanFactory);
                // 注册beanFactory的后置处理
                registerBeanPostProcessors(beanFactory);
                // 初始化上下文的消息
                initMessageSource();
                // 初始化上下的事件
                initApplicationEventMulticaster();
                // 初始化一些特殊的bean
                onRefresh();
                // 检查一些监听的bean并注册到容器中
                registerListeners();
                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);
                // 发布容器事件,结束Refresh过程
                finishRefresh();
            }
            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // 销毁已经生成的bean
                destroyBeans();
                // 重置激活状态.
                cancelRefresh(ex);
                throw ex;
            }

            finally {
            
                resetCommonCaches();
            }
        }
    }

beanDefinition信息是通过ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()里的refreshBeanFactory()来完成的,而这个方法则是在AbstractRefreshableApplicationContext实现的。

@Override
    protected final void refreshBeanFactory() throws BeansException {
            //如果容器已经存在,那么销毁并且关闭该容器,保证每次产生的都是新的容器
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
                   //创建基础的BeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
                   //载入BeanDefinition的信息
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

DefaultListableBeanFactory其实是一个最基础的容器,很多容器都是基于这个容器来作扩展,那么这个容器里自然也包含了很多基础重要的功能,那么通过loadBeanDefinitions()来完成BeanDefinition信息的载入的,这里是委托子类来完成这个工作的。

//抽象类,具体的resource定位跟BeanDefinition的载入是委托子类来完成的
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
            throws BeansException, IOException;


//这是loadBeanDefinitions的具体实现
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//创建XmlBeanDefinitionReader,并通过回调设置到beanFactory里面去
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// 使用此上下文的资源加载环境配置beanFactory
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//启动bean信息的载入过程
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }
//这里应该算是容器初始化第一步resource定位,首先得到beanDefinition信息的Resource定位
//然后通过XmlBeanDefinitionReader来读取
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//通过resource来定位
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
//通过文件路径来定位
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }


public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException {
//获取ResourceLoader
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        }
              //判断ResourceLoader的路径模式,
        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            try {
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                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 {
            // Can only load single resources by absolute URL.
            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;
        }
    }

getResourceByPath被子类FileSystemXmlApplicationContext实现,最终返回FileSystemResource对象,通过这个对象,Spring进行相关的I/O操作,完成beanDefinition的定位。
总结下Resource定位BeanDefinition的流程
1.FileSystemXmlApplicationContext里调用refresh()方法初始化IoC容器。
2.在refresh()方法里调用obtainFreshBeanFactory()里面的refreshBeanFactory()来完成BeanDefinition的定位,而refreshBeanFactory()是由子类AbstractRefreshableApplicationContext来实现的。
3.refreshBeanFactory()中是通过loadBeanDefinitions()来完成BeanDefinition的定位,而loadBeanDefinitions()是一个抽象的方法,具体由AbstractBeanDefinitionReader里的loadBeanDefinitions()来实现。
4.在loadBeanDefinitions()通过DefaultResourceLoader的getResource方法里返回resource对象。

  • 载入:BeanDefinition的信息已经定位到了,第二步就是把定义的BeanDefinition在Ioc容器中转化成一个Spring内部标示的数据结构的过程。
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 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 {
                  //准备读取xml文件
                InputStream inputStream = encodedResource.getResource().getInputStream();

                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                  //具体的读取过程是在doLoadBeanDefinitions()这个方法里完成
                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } finally {
                    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;
        }
    }
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            int validationMode = getValidationModeForResource(resource);
              //这里通过documentLoader来读取xml最终获取Document对象
            Document doc = this.documentLoader.loadDocument(
                    inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
             //这里通过registerBeanDefinitions()方法完成BeanDefinition的解析
            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);
        }
    }

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
          //获取BeanDefinitionDocumentReader对xml对BeanDefinition进行解析
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        documentReader.setEnvironment(this.getEnvironment());
        int countBefore = getRegistry().getBeanDefinitionCount();
       //具体解析是在registerBeanDefinitions()这个方法里进行对
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
        Element root = doc.getDocumentElement();
             //注册BeanDefinition
        doRegisterBeanDefinitions(root);
    }

protected void doRegisterBeanDefinitions(Element root) {
        //委托父类解析
        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;
                }
            }
        }

        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);

        this.delegate = parent;
    }

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //对xml里根节点下所有对子节点进行解析
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }


    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            //如果为bean的话 解析BeanDefinition
            processBeanDefinition(ele, delegate);
        }//beans
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // 递归解析
            doRegisterBeanDefinitions(ele);
        }
    }
 
    
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
 
}

首先通过调用XML的解析器得到Document对象,此时这些Document对象并没有按照Spring的Bean规则进行解析,在完成通用的XML解析以后,才是按照Spring Bean规则进行解析的地方,这个过程在documentReader中实现,使用的documentReader是默认设置好的DefaultBeanDefinitionDocumentReader。

  • 注册:将抽象好的BeanDefinition统一注册到IoC容器中,IoC容器是通过hashMap来维护BeanDefinition信息的,key为beanName,value为BeanDefinition。
/** Map of bean definition objects, keyed by bean name */
    private final Map beanDefinitionMap = new ConcurrentHashMap(256);

BeanDefinition的注册是发生在BeanDefinition信息载入之后的,

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition oldBeanDefinition;
              //如果beanName已经在map里存在,那么抛出异常
        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
        if (oldBeanDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                        "': There is already [" + oldBeanDefinition + "] bound.");
            }
            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(oldBeanDefinition)) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
                  
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            if (hasBeanCreationStarted()) {

           // 使用synchronize为了保证数据一致性,key为bean的名字,key为beanDefinition信息
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

这样就完成了beanDefinition在IoC容器中的注册;
下一篇会大概分析下依赖注入的过程, 第一次写这种源码分析的文章,思路还是比较混乱,还请大家多多指教,共同进步!

你可能感兴趣的:(SpringIoC-容器初始化过程)