Spring 框架学习(三):IoC 容器

Spring 框架学习(三):IoC 容器

概述

IoC 容器的核心是依赖反转模式。许多应用都是由两个或多个类通过彼此的合作来实现业务逻辑的,这是的每个对象都需要与其合作对象的引用。如果这个获取过程要靠自己实现,那将导致代码高度耦合并且难以测试。在 Spring 中通过把依赖对象的获取交给 IoC 容器来完成,在解耦代码的同时提高了代码的可测试性。

对依赖关系的统一管理,在一定程度上也降低了面向对象系统的复杂性。

在 Spring IoC 容器设计中,有两个主要的容器系列:一个是实现 BeanFactory 接口的简单容器系列,只实现了容器最基本的功能;另一个是 ApplicationContext 应用上下文,它作为容器的高级形态,增加了许多面向框架的特性,同时对应用环境作了许多适配。

BeanFactory 容器

Spring 框架学习(三):IoC 容器_第1张图片
XmlBeanFactory 类图.png
  1. BeanFactory 定义了容器最基本的接口:获取对象 getBean、判断是否包含 containsBean等。
  2. HierarchicalBeanFactory 增加了双亲 IoC 容器的管理功能:getParentBeanFactory 接口。
  3. ConfigurableBeanFactory 增加了设置双亲 IoC 容器的接口:setParentBeanFactory,Bean 后置处理器的添加:addBeanPostProcessor 等等。
  4. DefaultListableBeanFactory 是一个基本 IoC 容器的实现。
  5. XmlBeanFactory 相比 DefaultListableBeanFactory 增加了对 xml 配置文件的支持。

ApplicationContext 容器

Spring 框架学习(三):IoC 容器_第2张图片
FileSystemXmlApplicationContext 类图.png
  1. ApplicationContext 同样继承了 HierarchicalBeanFactory、BeanFactory 接口。
  2. ConfigurableWebApplication 也继承了 ConfigurableBeanFactory 接口。
  3. ApplicationContext 通过继承 MessageSource、ApplicationEventPuhlisher、ResourceLoader 接口,增加了许多高级特性。
  4. FileSystemXmlApplicationContext 是一个完整的容器实现,从文件系统读取 xml 配置来初始化容器。

容器初始化过程

我们以 FileSystemXmlApplicationContext 为例来查看容器初始化过程,其入口是构造方法:

    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
        // 设置双亲容器               
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            // 读取配置,初始化容器
            refresh();
        }
    }

refresh 方法负责初始化容器的一系列操作,具体有哪些操作看该方法的大纲即可知道:

    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 做准备操作,加载 placeholder 里配置的环境变量,校验所需环境变量是否全部存在
            prepareRefresh();

            // 创建 BeanFactory,解析 xml 配置,将 bean 定义加载到 map 中
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 一些准备工作,比如设置 ClassLoader、StandardBeanExpressionResolver、BeanPostProcessor
            prepareBeanFactory(beanFactory);

            try {
                // 又设置了一些 BeanPostProcessor
                postProcessBeanFactory(beanFactory);

                // 调用 BeanFactory 后处理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注册 Bean 的后处理器,前面是 BeanFactory 后处理器,这里是 Bean 的
                registerBeanPostProcessors(beanFactory);

                // 初始化消息源
                initMessageSource();

                // 初始化事件机制
                initApplicationEventMulticaster();

                // 初始化其他特殊的 bean
                onRefresh();

                // 注册事件 Listener
                registerListeners();

                // 初始化所有单例 Bean,非单例 Bean 是在 getBean 的时候初始化的
                finishBeanFactoryInitialization(beanFactory);

                // 发布容器初始化完成事件
                finishRefresh();
            } catch (BeansException ex) {
                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

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

                // Propagate exception to caller.
                throw ex;
            }
        }
    }

比较重要的是以下两步:

  1. 加载配置,创建 Bean 工厂:obtainFreshBeanFactory。
  2. 初始化所以单例 Bean:finishBeanFactoryInitialization。

obtainFreshBeanFactory

obtainFreshBeanFactory 加载配置,创建 BeanFactory 的调用顺序如下图所示:

Spring 框架学习(三):IoC 容器_第3张图片
obtainFreshBeanFactory 时序图.png

最终调用 BeanDefinitionParserDelegate 类的 parseBeanDefinitionElement 解析 bean 的配置。同时也会调用 parseCustomElement 解析其他配置,该方法最终会调用 NamespaceHandlerSupport 里注册的 BeanDefinitionParser 来解析这些特殊的配置。

public class ContextNamespaceHandler extends NamespaceHandlerSupport {

    public void init() {
        registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
        registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
        registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
        registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
        registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
        registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
    }
}

finishBeanFactoryInitialization

finishBeanFactoryInitialization 这一步会初始化所有单例的 Bean,非单例的 Bean 会在用户调用 getBean 方法的时候被初始化,单例的则是由 Spring 框架来调用 getBean 方法进行实例化。

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // Initialize conversion service for this context.
        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
                beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
            beanFactory.setConversionService(
                    beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
        }

        // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        for (String weaverAwareName : weaverAwareNames) {
            getBean(weaverAwareName);
        }

        // Stop using the temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(null);

        // Allow for caching all bean definition metadata, not expecting further changes.
        beanFactory.freezeConfiguration();

        // Instantiate all remaining (non-lazy-init) singletons.
        beanFactory.preInstantiateSingletons();
    }
    // in DefaultListableBeanFactory.java
    public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isInfoEnabled()) {
            this.logger.info("Pre-instantiating singletons in " + this);
        }
        List beanNames;
        synchronized (this.beanDefinitionMap) {
            // Iterate over a copy to allow for init methods which in turn register new bean definitions.
            // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
            beanNames = new ArrayList(this.beanDefinitionNames);
        }
        for (String beanName : beanNames) {
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                if (isFactoryBean(beanName)) {
                    final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged(new PrivilegedAction() {
                            public Boolean run() {
                                return ((SmartFactoryBean) factory).isEagerInit();
                            }
                        }, getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        // 调用 getBean 方法触发 Bean 的创建
                        getBean(beanName);
                    }
                }
                else {
                    getBean(beanName);
                }
            }
        }
    }   

getBean

getBean 方法调用了 createBean,时序图如下:

Spring 框架学习(三):IoC 容器_第4张图片
createBean 时序图.png

主要分为以下几步:

  1. 创建 Bean 实例:createBeanInstance。
  2. 填充配置的属性值:populateBean。
  3. 调用初始化方法:initializeBean。
  4. 注册 Bean 的销毁方法:registerDisposableBeanIfNecessary。

总结

Spring IoC 容器主要负责管理 Bean 的生命周期,Bean 都是放在 BeanFactory 工厂类中管理的,Bean 的配置以 xml 为主。那么初始化的过程,主要就是:

  1. 创建 BeanFactory。
  2. 解析 xml 配置,Bean 定义存储到 BeanFactory。
  3. 实例化 Bean,填充 Bean 的属性值,调用其初始化方法。

你可能感兴趣的:(Spring 框架学习(三):IoC 容器)