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

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值