SpringJava技术升华

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

2019-02-07  本文已影响54人  程序员Anthony

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的类关系图中可以看到如下:


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不具有的特性,如:

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的原理和功能。
总结一下这段代码包含的步骤:

在上面的过程中,创建和配置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本身的对象是通过在前面加上&来完成的。

上一篇 下一篇

猜你喜欢

热点阅读