Spring----IoC容器源码分析----初始化过程

一、在Spring IoC容器的设计中,有两个主要的容器系列:

  • 一个是实现BeanFactory接口的简单容器系列,这系列的容器只实现了容器的最基本功能。
  • 另一个是ApplicationContext应用上下文,它作为容器的高级形态而存在。应用上下文在简单容器的基础上,增加了许多面向框架的特性,同时对应用环境作了许多适配。

二、Spring中Ioc容器主要接口设计

Spring----IoC容器源码分析----初始化过程_第1张图片

  • 红色这一条是一条主要的设计路径。
  1. BeanFactory定义了基本的IoC容器的规范。包括了getBean()这样的IoC容器的基本方法(从容器中获取Bean)。
  2. HierarchicalBeanFactory接口在继承BeanFactory之后,增加了getParentBeanFactory()的接口功能,使BeanFactory具备了双亲IoC容器的管理功能。
  3. ConfigurableBeanFactory接口中,主要定义了一些对BeanFactory的配置功能。比如通过setParentBeanFactory()设置双亲IoC容器,addBeanPostProcessor()配置Bean后置处理。
  • 蓝色线是以ApplicationContext为核心的接口设计
  1. 在ListableBeanFactory中,细化了许多BeanFactory的接口功能,比如getBeanDefinitionNames()方法。
  2. HierarchicalBeanFactory上面提到了。
  3. ApplicationContext接口,通过集成MessageSource、ResourceLoader、ApplicationEventPublisher接口,在BeanFactory简单IoC容器的基础上添加了许多对高级容器的支持。
  • DefaultListableBeanFactory,这个基本IoC容器的实现就是实现了ConfigurableBeanFactory,从而成为一个简单的IoC容器的实现。XmlBeanFactory都是在DefaultListableBeanFactory基础上做扩展。

三、IoC容器的初始化过程

        简单来说,IoC容器的初始化是由AbstractApplicationContext中的refresh()方法来启动的,这个方法标志着IoC容器的正式启动。具体分为:BeanDifinition的Resource定位、载入和注册三个基本过程。Spring把这三个过程分开,可以让用户更加灵活地对这三个过程进行剪裁或扩展。

3.1 BeanDifiniton的Resource定位

  • 以编程方式使用DefaultListableBeanFactory时,首先定义一个Resource来定位容器使用的BeanDifinition。这时使用的是ClassPathResource,这时Spring会在类路径中去寻找一文件形式存在的BeanDifinition信息。这里定义的Resource需要通过BeanDefinitionReader来进行处理。
ClassPathResource classPathResource = new ClassPathResource("/beans.xml");
  • 以FileSystemXmlApplicationContext为例,下图是相应的继承关系

Spring----IoC容器源码分析----初始化过程_第2张图片

从上图中可看出,FileSystemXmlApplicationContext通过继承AbstractApplicationContext具备了ResourceLoader读入以Rescource定义的BeanDefinition的能力。代码内容如下:

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
	public FileSystemXmlApplicationContext() {
	}
	
	public FileSystemXmlApplicationContext(ApplicationContext parent) {
		super(parent);
	}
	//这个构造函数的configLocation包含的是BeanDefiniton所在的文件路径。
	public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}
	//这个构造函数的允许configLocation包含多个BeanDefiniton所在的文件路径。
	public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
		this(configLocations, true, null);
	}
	//这个构造函数的允许configLocation包含多个BeanDefiniton所在的文件路径,且还允许指定自己的双    
        //亲IoC容器
	public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
		this(configLocations, true, parent);
	}

	
	public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
		this(configLocations, refresh, null);
	}

	//在对象的初始化过程中,调用refresh函数载入BeanDefition,这个refresh启动了BeanDefinition的 
        //载入过程
	public FileSystemXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}

      //这个是应用于文件系统中Rescource的实现,通过构造一个FileSystemResource来得到一个在文件系统 
      //中定位的BeanDefition,这个getResourceByPath是在BeanDefinitionReader的 
      //loadBeanDefinition中被调用的,loadBeanDefinition采用了模板模式,具体的定位实现实际上是由 
      //各个子类来完成的。
	@Override
	protected Resource getResourceByPath(String path) {
		if (path.startsWith("/")) {
			path = path.substring(1);
		}
		return new FileSystemResource(path);
	}

}
  • 在初始化FileSystemXmlApplicationContext的过程中,通过IoC容器的初始化的refresh来启动整个调用,使用的IoC容器是DefaultListableBeanFactory。具体的资源载入在XmlBeanDefinitonReader读入BeanDefinition时完成,在XmlBeanDefinitonReader的基类AbstractBeanDefinitionReader中可以看到这个载入过程的具体实现。
  • AbstractRefreshableApplicationContext对容器的初始化
   
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        //判断,如果已经建立了BeanFactory,则销毁并关闭改BeanFactory
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        //这里是创建并设置持有的DefaultListableBeanFactory的地方同时调用loadBeanDefinitions()再载入BeanDefinition的信息
        try {
            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);
        }
    }

    /**
     * 这就是在上下文中创建DefaultListableBeanFactory的地方,而getInternalParentBeanFactory()的具体实现可以参看AbstractApplicationContext
     * 中的实现,会根据容器已有的双亲IoC容器的信息来生成DefaultListableBeanFactory的双亲Ioc容器
     * @return
     */
    protected DefaultListableBeanFactory createBeanFactory() {
        return new DefaultListableBeanFactory(getInternalParentBeanFactory());
    }
//AbstractBeanDefinitionReader中loadBeanDefinitions具体实现
public int loadBeanDefinitions(String location, @Nullable Set actualResources) throws BeanDefinitionStoreException {
        //这里取得ResourceLoader,使用的是DefaultResourceLoader
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
        }
        //这里对Resource的路径模式进行解析,比如我们设定的各种Ant格式的路径定义,得到需要的Resource集合,这些Resource集合指向
        //我们已经定义好的BeanDefinition信息,可以是多个文件。
        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            try {
                //调用DefaultResourceLoader的getResources()完成具体的Resource定位。
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                int count = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    Collections.addAll(actualResources, resources);
                }
                if (logger.isTraceEnabled()) {
                    logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
                }
                return count;
            }
            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 count = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isTraceEnabled()) {
                logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
            }
            return count;
        }
    }

    //DefaultResourceLoader的具体定位过程
    @Override
    public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");

        for (ProtocolResolver protocolResolver : this.protocolResolvers) {
            Resource resource = protocolResolver.resolve(location, this);
            if (resource != null) {
                return resource;
            }
        }

        if (location.startsWith("/")) {
            return getResourceByPath(location);
        }
        //这里处理带有classpath标识的Resource
        else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
        }
        else {
            try {
                //这里处理URL标识的Resource
                URL url = new URL(location);
                return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
            }
            catch (MalformedURLException ex) {
                //如果既不是classpath也不是URL标识的Resource定位,则交给getResourceByPath,默认是得到一个ClassPathContextResource
                //,这个方法往往子类来实现。
                return getResourceByPath(location);
            }
        }
    }
    //FileSystemXmlApplicationContext的重写,如果是其他的ApplicationContext就会生成其他种类    
    @Override
	protected Resource getResourceByPath(String path) {
		if (path.startsWith("/")) {
			path = path.substring(1);
		}
		return new FileSystemResource(path);
	}

3.2 BeanDefinition的载入和解析.

  • 对IoC容器来说,这个载入过程,相当于把定义的BeanDefinition在IoC容器中转化成一个Spring内部表示的数据结构的过程。
  • 首先IoC容器的初始化入口,就是AbstractApplicationContext的refresh()方法,它详细的描述了整个ApplicationContext的初始化过程,比如BeanFactory的更新,MessageSource和PostProcessor的注册等等。

下面是refresh()的代码:

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            //这是子类启动refreshBeanFactory()的地方
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            //设置一些BeanFactory参数
            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);
                }

                // 为防止Bean资源占用,在异常处理中,销毁已经在前面过程中生成的单例Bean
                destroyBeans();

                // 重置“active”表示
                cancelRefresh(ex);

                throw ex;
            } finally {
                // 清除不需要的缓存
                resetCommonCaches();
            }
        }
    }
  • obtainFreshBeanFactory();

  1. protected final void refreshBeanFactory() throws BeansException {
            if (hasBeanFactory()) {
                destroyBeans();
                closeBeanFactory();
            }
            try {
                //创建IoC容器,这里使用的是DefaultListableBeanFactory
                DefaultListableBeanFactory beanFactory = createBeanFactory();
                beanFactory.setSerializationId(getId());
                customizeBeanFactory(beanFactory);
                //启动对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);
            }
        }

     

    Spring----IoC容器源码分析----初始化过程_第3张图片

  • 这里调用的loadBeanDefinition()是一个抽象方法。实际载入的过程发生在AbstractRefreshableApplicaitonContext
     //这里实现了loadBeanDefinitions
        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            // 创建XmlBeanDefinitionReader,并通过回调设置到BeanFactory中去
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
            // Configure the bean definition reader with this context's
            // resource loading environment.
            beanDefinitionReader.setEnvironment(this.getEnvironment());
            //这里设置XmlBeanDefinitionReader,为XmlBeanDefinitionReader配ResourceLoader,因为DefaultResourceLoader是父类,所以能直接用。
            beanDefinitionReader.setResourceLoader(this);
            beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    
            //这里启动Bean定义信息载入的过程
            initBeanDefinitionReader(beanDefinitionReader);
            loadBeanDefinitions(beanDefinitionReader);
        }
  • 接着就是loadBeanDefinition()调用的地方,首先得到BeanDefinition信息的Resource定位,然后直接调用XmlBeanDefinition来读取,具体的载入过程是委托给 BeanDefinitionReader完成的。
   protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        //以Resource的方式获取配置文件的资源位置
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        //以String的形式获取配置文件的位置
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }

 

  public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        //如果Resource为空,则停止BeanDefinition的载入
        //启动载入BeanDefinition的过程,这个过程会遍历整个Resource集合所包含的BeanDefinition信息。
        Assert.notNull(resources, "Resource array must not be null");
        int count = 0;
        for (Resource resource : resources) {
            //这里调用的loadBeanDefinitions(Resource resource)在AbstractBeanDefinitionReader中没有实现,
            //是一个接口方法,具体的实现在XmlBeanDefinitionReader中。
            count += loadBeanDefinitions(resource);
        }
        return count;
    }
//调用入口
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return loadBeanDefinitions(new EncodedResource(resource));
    }

    //这里是载入Xml形式的BeanDefinition的地方
    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!");
        }
        //这里得到XML文件,并得到IO的InputSource准备读取
        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();
            }
        }
    }

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

        try {
            //获取XMl文件的Document对象,由documentLoader(DefaultDocumentLoader)完成
            Document doc = doLoadDocument(inputSource, resource);
            //这里启动的是对BeanDefinition解析的详细过程,会用到Spring的Bean配置规则。
            int count = registerBeanDefinitions(doc, resource);
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            return count;
        }
        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进行解析
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        //具体的解析过程在这个registerBeanDefinitions中完成。
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

 

//位于DefaultBeanDefinitionDocumentReader
    //解析完文件,注册
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //获取到BeanDefinition
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                //注册到IoC容器中
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

3.3、BeanDefinition在IoC容器中的注册 

//DefaultListableBeanFactory
    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 existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                //BeanDefinition已存在,又不允许覆盖,则抛异常
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + existingDefinition +
                            "] 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 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 (existingDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

到这里,就完成了BeanDefinition的注册,就完成了IoC容器的初始化过程。此时,在使用的IoC容器DefaultListableBeanFactory中已经建立了整个Bean的配置信息,而且这些BeanDefinition已经可以被容器使用了。

你可能感兴趣的:(Spring)