Spring 核心之 Ioc容器实现

Ioc 是在Spring中, 一种控制(依赖)反转模式的实现载体, 而这种模式采用倒置注入的方式解决对象依赖问题,这样可以简化对象依赖管理, 在很大程度上降低面向对象系统开发的复杂性, 控制反转是Spring框架的核心.


1 . 先看一下Spring Ioc设计所关系到的一系列接口与类的继承实现关系
接口继续关系图

最后的 (ClassPathXmlApplicationContext) 和 (XmlWebApplicationContext) 就是我们平时做SpringMVC开发常用到的初始化类对象。

2 . 介绍说明一下上图中出现的各个接口的作用

(1). BeanFactory: 访问获取 spring bean 容器中 bean 实例最基础的接口.
(2). HierarchicalBeanFactory: 在 BeanFactory 的基础上添加了继承功能, bean工厂可以包含父容器;
(3). ConfigurableBeanFactory: 为 BeanFactory 添加配置能力, 指定bean初始化方式等;
(4). ListableBeanFactory: 可以加载获取到一系列的bean对象;
(5). ConfigurableListableBeanFactory: 提供了分析与修改bean实例的能力, 及单例的预实例化;
(6). AutowireCapableBeanFactory: 可以通过注解的方式为一个bean实例提供它所需的其他bean做为它的属性;
(7). SimpleAliasRegistry: 一个简单的bean别名注册器;
(8). DefaultSingletonBeanRegistry: 注册单例对象实例并运行被所有需要注册的bean所共享, 根据bean name获取;
(9). FactoryBeanRegistrySupport: 在DefaultSingletonBeanRegistry上再做了层封装, 相当于一个管理对象可以安全被用户使用;
(10). AbstractBeanFactory: 具有可配置bean工厂的全部功能, 同时提供了单例bean缓存, 可以处理, bean别名, bean定义及其子类定义合并, 还有bean的销毁方法等;
(11). AbstractAutowireCapableBeanFactory: 实现了默认的bean创建方式, 同时添加了注解注入的功能;
(12). BeanDefinitionRegistry: 注册bean定义在父子上下文容器里面;
(13). DefaultListableBeanFactory: 一个默认的且完整的 Bean Factory 实现类, 具有bean工厂以上全部功能;
(14). EnvironmentCapable: 具有获得一个环境信息对象的能力;
(15). MessageSource: 处理相关信息源的能力, 比如支持国际化的实现等
(16). ApplicationEventPublisher: 支持应用程序事件为bean生命周期管理提供便利;
(17). ResourcePatternResolver: 获取访问资源;
(18). Lifecycle: 定义开始与结束的生命周期控制;
(19). Closeable: 用于释放或关闭某些资源对象数据;
(20). ApplicationContext: Spring的核心接口, 提供对一个应用的配置; 这个对象时只读的, 除非它的子对象进行重新载入;
(21). ConfigurableApplicationContext: 结合了ApplicationContext, 添加了额外的应用程序生命周期等处理入口;
(22). WebApplicationContext: 相比ApplicationContext添加了获取ServletContext的方法, 以支持web应用;
(23). AbstractApplicationContext: ApplicationContext 的一个抽象实现类, 是SpringIoc容器初始化时的关键对象, 里面有一些列bean创建, 资源处理, 过滤器添加, 相关事件通知等;
(24). InitializingBean: 当一个bean实例所依赖所有对象都被Bean factory注入后, 会回调这个接口中的afterPropertiesSet方法;
(25). AbstractRefreshableApplicationContext: 实现了AbstractApplicationContext中的refreshBeanFactory方法, 进行spring bean factory的默认创建和bean定义解析载入;
(26). BeanNameAware: 可以得到bean的名称;
(27). AbstractRefreshableConfigApplicationContext: 在AbstractRefreshableApplicationContext的基础上引入了BeanNameAware和InitializingBean方法;
(28). AbstractXmlApplicationContext: 实现了个装载bean的方法;
(29). ClassPathXmlApplicationContext: 类路径下加载bean配置文件;
(30). ConfigurableWebApplicationContext: 结合WebApplicationContext与ConfigurableApplicationContext;
(31). ThemeSource: 获取Theme对象, 后面做资源转换;
(32). FileSystemXmlApplicationContext: 文件系统路径下加载bean配置文件;
(33). AbstractRefreshableWebApplicationContext:
(34). XmlWebApplicationContext: Spring Web应用默认配置在”org.springframework.web.context.ContextLoader.properties”中的, 由”org.springframework.web.context.ContextLoaderListener”加载启动应用上下文的Class对象, 同时里面有bean定义解析的方法实现;
(35). XmlBeanDefinitionReader: 读取解析spring配置xml文件中的bean定义信息及其他配置信息;
(36). BeanDefinition: Spring bean factory中对bean对象定义的数据对象, 也是Spring Ioc中的核心数据结构对象;

Spring容器加载启动过程

3 . Spring Web应用由web.xml加载启动
(1). 首先会有如下两个配置项, 分别在ContextLoader与FrameworkServlet两个内里面有WebApplicationContext的创建加载解析操作;

    <!-- Spring Listener 需要加载的配置文件 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/spring-context.xml</param-value>
    </context-param>
    // 配置Listener加载Spring应用上下文的父容器
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    // 配置Listener加载Spring应用上下文的子容器
    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/spring-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

(2). 从配置文件xml解析bean与项目配置信息的关键过程

    /**
     * Instantiate the WebApplicationContext for this servlet, either a default
     * {@link org.springframework.web.context.support.XmlWebApplicationContext}
     * or a {@link #setContextClass custom context class}, if set.
     * <p>This implementation expects custom contexts to implement the
     * {@link org.springframework.web.context.ConfigurableWebApplicationContext}
     * interface. Can be overridden in subclasses.
     * <p>Do not forget to register this servlet instance as application listener on the
     * created context (for triggering its {@link #onRefresh callback}, and to call
     * {@link org.springframework.context.ConfigurableApplicationContext#refresh()}
     * before returning the context instance.
     * @param parent the parent ApplicationContext to use, or {@code null} if none
     * @return the WebApplicationContext for this servlet
     * @see org.springframework.web.context.support.XmlWebApplicationContext
     */
    protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
        Class<?> contextClass = getContextClass();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Servlet with name '" + getServletName() +
                    "' will try to create custom WebApplicationContext context of class '" +
                    contextClass.getName() + "'" + ", using parent context [" + parent + "]");
        }
        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            throw new ApplicationContextException(
                    "Fatal initialization error in servlet with name '" + getServletName() +
                    "': custom WebApplicationContext class [" + contextClass.getName() +
                    "] is not of type ConfigurableWebApplicationContext");
        }
        ConfigurableWebApplicationContext wac =
                (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

        wac.setEnvironment(getEnvironment());
        wac.setParent(parent);
        wac.setConfigLocation(getContextConfigLocation());

        configureAndRefreshWebApplicationContext(wac);

        return wac;
    }

(3). 创建完WebApplicationContext后进行初始化

    protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
        if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
            // The application context id is still set to its original default value
            // -> assign a more useful id based on available information
            if (this.contextId != null) {
                wac.setId(this.contextId);
            }
            else {
                // Generate default id...
                wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                        ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName());
            }
        }

        wac.setServletContext(getServletContext());
        wac.setServletConfig(getServletConfig());
        wac.setNamespace(getNamespace());
        wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

        // The wac environment's #initPropertySources will be called in any case when the context
        // is refreshed; do it eagerly here to ensure servlet property sources are in place for
        // use in any post-processing or initialization that occurs below prior to #refresh
        ConfigurableEnvironment env = wac.getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
        }

        postProcessWebApplicationContext(wac);
        applyInitializers(wac);
        wac.refresh();
    }

(4). 调用ConfigurableApplicationContext接口的refresh, 这个方法很关键, 里面是真正的bean创建与装配,

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing
            // 设置标志量, 这个方式是同步执行的
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            // 获取到beanFactory, 里面包含了所有bean的定义信息,别名信息等
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            // 设置一些默认属性, 包括类加载器, 表达式处理器, 过程处理器和context回调处理器等
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                // 可以加入额外的bean初始过程处理器, 对于web应用这里就会加入一个为ServletConfigAware类型的bean对象设置servlet上下文的处理器;
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                // 反转提取其他过程处理器,这里会有一个BeanDefinitionRegistryPostProcessor处理器, 如果项目使用了Mybatis, 那还会有个MapperScannerConfigurer的处理器(进行mybatis里面mapper扫描与dao实例植入);
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 注册一些拦截bean创建过程的处理器, 比如注解注入啊, requestmapping, aop切入等
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                // 初始化应用上下问的信息源
                initMessageSource();

                // Initialize event multicaster for this context.
                // 为应用上下文注册一个事件多路广播器
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                // 处理themeSource
                onRefresh();

                // Check for listener beans and register them.
                // 为事件广播器设置进去需要通知的监听器的名称
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                // 单例Bean初始化与装配及相关接口回调
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                // 事件发布
                finishRefresh();
            }

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

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

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

                // Propagate exception to caller.
                throw ex;
            }

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

4 . 几个有用的与Spring上下文及bean初始化进程相关的接口
(1). BeanNameAware: setBeanName方法,可以让该bean感知到在beanFactory中自己的名字; 调度时间是在该bean被实例化并装配好自身所依赖的属性后, 但在 InitializingBean#afterPropertiesSet() 之前;
(2). BeanClassLoaderAware: setBeanClassLoader方法,可以让该bean感知到它是被哪个类加载器加载的;调度时间紧跟在 BeanNameAware 之后;
(3). BeanClassLoaderAware: setBeanFactory方法,可以让该bean感知到它所在的BeanFactory;调度时间紧跟在 BeanClassLoaderAware之后;
(4). InitializingBean: afterPropertiesSet方法, 当一个bean被完全装配完后调用的方法;此时这个bean已经具有了它应该有的所有业务功能;
(5). DisposableBean: destroy方法, 在bean被销毁前调用, 可以做一些资源释放或者信息发送等操作;
(6). ApplicationContextAware: setApplicationContext方法, 可以得到spring应用上下文的引用;

猜你喜欢

转载自blog.csdn.net/hinstenyhisoka/article/details/53216481