美文网首页程序员Spring
Spring 框架学习(三):IoC 容器

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

作者: albon | 来源:发表于2017-10-24 11:18 被阅读62次

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

概述

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

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

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

BeanFactory 容器

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

ApplicationContext 容器

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 的调用顺序如下图所示:

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<String> 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<String>(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<Boolean>() {
                            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,时序图如下:

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 的属性值,调用其初始化方法。

相关文章

  • 2.Spring IoC 容器

    1.Spring IoC 容器 IoC 容器 Spring 容器是 Spring 框架的核心。容器将创建对象,把它...

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

    Spring 框架学习(三):IoC 容器 概述 IoC 容器的核心是依赖反转模式。许多应用都是由两个或多个类通过...

  • Spring原理简述

    一、什么是Spring容器? Spring容器,也称Spring Ioc容器或bean容器,是Spring框架的核...

  • Spring IoC 容器

    1.1 spring IoC容器和beans的简介 Spring 框架的最核心基础的功能是IoC(控制反转)容器,...

  • 1、IOC(容器)&DI(依赖注入)

    1、什么是IOC?ioc是spring容器,ioc是spring框架的核心,ioc可以分为两类,BeanFacto...

  • 详解Spring IOC

    Spring IOC其实很简单  我们通常提到的Spring IOC,实际上是指Spring框架提供的IOC容器实...

  • 2020-03-13 spring 框架

    Spring框架 Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架 IOC 控制反转(In...

  • Spring中的两大核心(Spring是一个IOC和AOP容器框架) IOC与aop IOC(spring的核心思...

  • Spring 容器简介

    1. 什么是容器 这里说的Spring容器一般就是指IOC容器,Spring 框架的最核心基础的功能是IOC(控制...

  • Spring框架

    Spring框架 Spring框架的七大模块 Spring Core:框架的最基础部分,提供 IoC 容器,对 b...

网友评论

    本文标题:Spring 框架学习(三):IoC 容器

    本文链接:https://www.haomeiwen.com/subject/iwbauxtx.html