美文网首页SpringJava技术升华
Spring 核心容器的实现之IOC容器的实现

Spring 核心容器的实现之IOC容器的实现

作者: 程序员Anthony | 来源:发表于2019-02-07 20:35 被阅读54次

2019年的第一篇文章,新的一年的计划是完成11*3,33篇文章,每一篇文章都会花至少2个小时进行创作。加油啦。

1 前言

Spring为开发者提供了一个一站式的轻量应用开发框架(平台)。在Spring中IOC容器和AOP模块是两大核心,类似与操作系统的Kernel。
通过使用Spring的IOC容器,可以对Java对象中的耦合关系方便的进行浏览,修改和维护。原来的对象-对象的关系,转化为了对象-IOC容器-对象的关系。完成了对象之间的关系解耦。本篇文章就准备从整体和细节角度分析一下Spring核心容器之一的IOC容器的实现。

2 Spring IOC容器的内容

Spring IoC:包含了最基本的IoC容器BeanFactory的接口和实现。ApplicationContext作为BeanFactory的高级形态供用户进行使用。ApplicationContext应用上下文,如FileSystemXmlApplicationContext,ClassPathXmlApplicationContext 是IoC容器中更面向框架的使用方式。为了便于开发,像国际化的消息源和应用支持事件这些特性,也都围绕这个模块中配合IoC容器来实现,这些功能围绕IoC基本容器和应用上下问,构成了整个Spring IoC模块设计的重要内容。

3 代码分析

3.1 IoC容器整体设计

Spring的Bean组件在org.springframework.beans包下,在这个包下面得解决了:Bean 的定义,Bean 的创建和Bean的解析。对于Spring的使用者来说主要关心的是这个Bean的创建过程。Bean的创建是典型的工厂模式,以BeanFactroy为核心。

这里从ApplicationContext着手开始分析,从ApplicationContext的类关系图中可以看到如下:


  • BeanFactory是基本的IoC容器 :从接口BeanFactory到HierarchicalBeanFactory再到ApplicationContext。在BeanFactory中定义了基本的IoC容器的规范,包含了getBean这样的IoC容器的基本方法。而HierarchicalBeanFactory在继承了BeanFactory之后是添加了getParentBeanFactory的接口功能。使得当前的BeanFactory具备了双亲IoC容器的管理功能。
  • ApplicationContext是一个高级形态的IoC容器:我们常用的应用上下文基本都是ConfigurableApplicationContext或WebApplicationContext。都是继承自ApplicaitonContext的。对于ApplicaitonContext接口,通过继承MessageSource,ResourceLoader,ApplicationEventPublisher从而完成了在BeanFactory基础上的许多高级特性的支持。
3.1.1 BeanFactory分析

BeanFactory 接口定义了IoC容器的基本形式和应当遵守的基本契约,并没有具体的实现。



接着我们来看看BeanFactory的一个实现类XmlBeanFactory的继承类图:


在Spring中,把DefaultListableBeanFactory当作一个默认的功能完整的IoC容器来使用。 XmlBeanFactory在继承了DefaultListableBeanFactory的基础上,增加支持读取XML文件的方式定义了这个IoC容器。如下所示:

类比ApplicationContext:我们可以看到的是XmlBeanFactory使用了DefaultListableBeanFactory作为基类。类似于我们之前的ApplicationContext,实现原理也和XmlBeanFactory一样,也是通过持有或者拓展BeanFactory的子类来实现IoC容器的功能。

由于XmlBeanFactory文档中已经标记为@deprecated的类,所以我们这里根据远离,使用编程的方式实现IoC容器的的过程,和上面XmlBeanFactory一样:


3.1.2 ApplicationContext分析

上面提到,ApplicationContext是一个高级形态的IoC容器,那么ApplicationContext提供了哪一些BeanFactory不具备的特性?

这里我们可以从上面ApplicationContext的继承关系图中看到,出了延伸于BeanFactory的类的话,其他就是BeanFactory不具有的特性,如:

  • 支持不同的信息源,通过扩展MessageSource实现。
  • 访问资源。通过对ResourceLoader和Resource的支持上,可以从不同地方得到Bean定义资源。
  • 支持应用事件。继承了接口ApplicationEventPublisher,从而在上下文中引入了事件机制。

3.2 IoC容器如何工作

3.2.1 以FileSystemXmlApplicationContext为入口

这里以FileSystemXmlApplicationContext 为入口,看看IoC容器是如何工作的。


在FileSystemXmlApplicationContext的设计中,主要关注的是这个refresh()过程,这会牵涉IoC容器启动的一系列复杂的操作都在这里面,但是这是在AbstractApplicationContext中实现的。不同的应用上下文对应着不同的读取BeanDefinition的方法,在FileSystemXmlApplicationContext中如下getResourcePath所示。


这里明确,以AbstractApplicationContext类 为研究中心
3.2.2 BeanFactory加载

代码片段1 这里来自以AbstractApplicationContext类 的refresh方法

@Override
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 为刷新准备新的context
            prepareRefresh();

            // 刷新所有BeanFactory子容器
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 创建BeanFactory后,添加一些Spring 需要的工具类
            prepareBeanFactory(beanFactory);

            try {
              // 在Bean Factory 初始化之后,可以继续配置更改
                postProcessBeanFactory(beanFactory);

                //执行BeanFactoryPostProcessor
                invokeBeanFactoryPostProcessors(beanFactory);

                // 创建Bean实例对象时添加一些自定义的操作
                registerBeanPostProcessors(beanFactory);

                // 初始化MessageSource
                initMessageSource();

                //初始化event multicaster
                initApplicationEventMulticaster();

                // 刷新由子类实现的方法
                onRefresh();

                // 检查和注册事件
                registerListeners();

                // 初始化non-lazy-init 单例bean
                finishBeanFactoryInitialization(beanFactory);

                // event事件
                finishRefresh();
            }

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

                // 销毁beans
                destroyBeans();


                cancelRefresh(ex);


                throw ex;
            }

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

这个方法是构建整个IoC容器的完整代码,了解里面的每一行代码,就了解了大部分Spring的原理和功能。
总结一下这段代码包含的步骤:

  • (1)构建BeanFactory,用于创建Bean
  • (2)注册可能感兴趣的事件
  • (3) 创建Bean实例对象
  • (4)触发被监听的事件

在上面的过程中,创建和配置BeanFactory,刷新配置的步骤由obtainFreshBeanFactory()方法完成,
进入方法内部,主要是刷新和获取BeanFactory


刷新beanFactory交给子类去实现,这里是AbstractRefreshableApplicationContext中实现代码:



上图所示的createBeanFactory会调用DefaultListableBeanFactory的createBeanFactory方法。然后下方的loadBeanDefinitions会进入
AbstractXmlApplicationContext的loadBeanDefinitions方法,到这里应该就完成了BeanFactory的创建工作。


接着回到代码清单1中,我们关注到 registerBeanPostProcessors(beanFactory)方法,也可以获取用户定义实现了BeanPostProcessor接口的子类。并把它注册到BeanFactory对象中的beanPostProcessors变量中。在BeanPostProcessor中声明了两个方法:



分别用于在Bean对象初始化时执行,可以执行用户自定义的操作。

3.2.3 创建Bean实例

回到代码清单1 ,Bean的实例化代码,是从 finishBeanFactoryInitialization(beanFactory)方法开始的。


    @Override
    public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }

        // 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.
        List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

        // Trigger initialization of all non-lazy singleton beans...
        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>() {
                            @Override
                            public Boolean run() {
                                return ((SmartFactoryBean<?>) factory).isEagerInit();
                            }
                        }, getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
                else {
                    getBean(beanName);
                }
            }
        }

        // Trigger post-initialization callback for all applicable beans...
        for (String beanName : beanNames) {
            Object singletonInstance = getSingleton(beanName);
            if (singletonInstance instanceof SmartInitializingSingleton) {
                final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged(new PrivilegedAction<Object>() {
                        @Override
                        public Object run() {
                            smartSingleton.afterSingletonsInstantiated();
                            return null;
                        }
                    }, getAccessControlContext());
                }
                else {
                    smartSingleton.afterSingletonsInstantiated();
                }
            }
        }
    }

如果一个类继承FactoryBean,用户可以自己定义产生实例对象的方法,只需实现它的getObject方法就可以了。这就上上面代码中出现的FactoryBean。Spring获取FactoryBean本身的对象是通过在前面加上&来完成的。

相关文章

网友评论

    本文标题:Spring 核心容器的实现之IOC容器的实现

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