[spring源码] 小白级别的源码解析ioc(二)

之前一篇,整体描述了一下 Spring的整体概况和 jar包的介绍。 现在开始进入具体的源码解析,从本篇开始,先介绍spring的ioc容器。之前也看过一些介绍spring源码的, 有的是只讲整体的接口,缺少和源码的结合,有的是一直源码跟进的讲解,由于类的调用太深, 导致看着看着就晕了。 所以自己决定动手写一遍,结合两者的优点。

1,spring ioc容器的整体设计

 

    该图摘自spring技术内幕。

    图中的两条线路是主要的两条接口设计线路图。

    整体接口系统都是以beanfactory和applicationContext为核心。

    beanfactory是ioc容器最基本的接口。

    applicationContext 是在继承了 beanfactory的基础上,新增了一些高级的ioc特性。

2,spring ioc容器设计详解

     这里采用相对原始的方式使用spring,方便深入了解springioc容器的初始化。其他的各种不同的实现,针对不懂得资源加载方式,扩展了一些功能,整体思路是相同的。

     

 ClassPathResource resource = new ClassPathResource("beans.xml");
 DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
 reader.loadBeanDefinitions(resource)

 

     主要分为了三个过程。 

     1.resource定位

     2.beanDefinition的载入。

     3.向ioc容器注册beanDefinition的过程。这个过程通过调用BeanDefinitionRegistry接口的实现来完成。

     在这里DefaultListableBeanFactory是一个纯粹的ioc容器,需要给他配置特定的读取器才能完成功能。而我们常用的application已经提供了一系列不同的resource,不需要手动指定。例如:

      FileSystemXmlApplicationContext 从文件系统中载入,ClassPathXmlApplicationContext 从class path载入,XmlWebApplicationContext 可以在web容器中载入。

    下面以FileSystemXmlApplicationContext为例详细的介绍。

     先给出整体的uml图。

      

   整个加载的入口不再过多的描述。

 public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException { 
        super(parent);
        setConfigLocations(configLocations);
       if (refresh) {
           refresh();
        }
}

 

直接找到FileSystemXmlApplicationContext的构造函数即可。refresh()方法就是这个ioc容器加载的入口,该方法的具体实现在AbstractApplicationContext。

   下面我不去按照源码一步步的跟进。而是去按照ioc容器的整体的一个加载流程,做介绍。有一个整体思路,大家在一步步的去跟进代码,也比较清晰。

   

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 刷新上下文
            prepareRefresh();
            //这里是在子类中启动refreshBeanFactort()的地方
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);
            try {
                // 设置beanFactory的后置处理
                postProcessBeanFactory(beanFactory);
                //调用beanFactory的后处理器,这些后处理器是在bean定义中向容器注册的
                invokeBeanFactoryPostProcessors(beanFactory);
                //注册bean的后处理器,在bean创建过程中调用
                registerBeanPostProcessors(beanFactory);
                //对上下文中的消息源进行初始化
                initMessageSource();
                //初始化上下文中的事件机制
                initApplicationEventMulticaster();
                //初始化其他的特殊bean
                onRefresh();
                //检查监听bean并且将这些bean向容器注册
                registerListeners();
                //实例化所有的(non-lazy-init)单利
                finishBeanFactoryInitialization(beanFactory);
                //发布容器事件,结束refresh过程
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

 

   Resource定位

     整体的调用链

     

 

protected final void refreshBeanFactory() throws BeansException {
//这里判断是否已经建立了beanFactory,如果存在就销毁并关闭
if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try {
       //这里就是在上下文中创建defaultListableBeanFactory的地方。 DefaultListableBeanFactory beanFactory
= createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }

 

 

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//这里取得resourceLoader,采用的是DefaultResourceLoader ResourceLoader resourceLoader
= getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try {
//这里是具体的加载 Resource的地方 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; } }

 

 

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<EncodedResource>(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();
            }
        }
    }

   BeanDefinition的载入和解析

    从abstractRefreshableApplicationContext的refreshBeanFactory方法开始入手,了解整个bean定义信息的载入过程。

    

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 创建 XmlBeanDefinitionReader 
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
     //为xmlbeanDefinitionReader 设置resourceloader beanDefinitionReader.setResourceLoader(
this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //启动bean定义信息载入过程 initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }

 

    下面是loadBeanDefinitions调用的地方,首先得到beanDefinition信息的resource定位,然后调用xmlBeanDefinitionReader来读取.

   

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        //以resource的方式获取配置文件的资源位置
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        //以String的形式获取
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }

   

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<EncodedResource>(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();
            }
        }
    }

 具体的读取过程在doLoadBeanDefinitions。

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
     //完成具体的文档读取 Document doc
= doLoadDocument(inputSource, resource);
     //按照spring的bean的语义要求进行解析并转化为容器的内部数据结构。
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); } }

 

     beanDefinition 的载入分为两部分。首先调用xml的解析器得到document对象。然后documentReader中按照spring的bean的规则进行解析。

    BeanDefinition的注册

    在DefaultListableBeanFactory中,通过一个map来持有载入的beanDefinition的。

/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

再DefaultListableBeanFactory中实现了beanDefinitionRegistry的接口,这个接口完成了beanDefinition向容器的注册。就是将解析得到的beandefinition设置到hashmap中。

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;

        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()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<String>(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);
        }
    }

 



posted @ 2017-05-18 16:46  鹊南  阅读(6546)  评论(0编辑  收藏  举报