spring源码学习之二 XmlWebApplicationContext类结构概述

先来看下XmlWebApplicationContext类UML图
Markdown
从上图可以看出,XmlWebApplicationContext实现了ConfigurableApplicationContext接口和WebApplicationContext接口.
在上一篇文章中说到通过XmlWebApplicationContext.refresh()方法来完成Spring上下文初始化配置工作,而refresh()方法是在ConfigurableApplicationContext接口中定义的.


/**
     * Load or refresh the persistent representation of the configuration,
     * which might an XML file, properties file, or relational database schema.
     * <p>As this is a startup method, it should destroy already created singletons
     * if it fails, to avoid dangling resources. In other words, after invocation
     * of that method, either all or no singletons at all should be instantiated.
     * @throws BeansException if the bean factory could not be initialized
     * @throws IllegalStateException if already initialized and multiple refresh
     * attempts are not supported
     */
void refresh() throws BeansException, IllegalStateException;

ConfigurableApplicationContext

该接口扩展了ApplicationContext接口同时扩展了Lifecycle, Closeable两个接口,对应实现方法在AbsctractApplicationContext抽象类中完成.

这里写图片描述

  • addApplicationListener 添加应用监听器
  • addBeanFactoryPostProcessor 添加bean工厂处理器
  • close() 重新定义了Closeable中的close()方法定义
  • setId(String) 对当前ApplicationContext指定一个ID
  • registerShutdownHook()对JVM Runtime注册一个关闭钩子线程,当JVM正常关闭时会先执行该线程然后再关闭JVM,可以查看AbstractApplicationContext中的实现方法,代码如下:
/**
     * Register a shutdown hook with the JVM runtime, closing this context
     * on JVM shutdown unless it has already been closed at that time.
     * <p>Delegates to {@code doClose()} for the actual closing procedure.
     * @see Runtime#addShutdownHook
     * @see #close()
     * @see #doClose()
     */
    @Override
    public void registerShutdownHook() {
        if (this.shutdownHook == null) {
            // No shutdown hook registered yet.
            this.shutdownHook = new Thread() {
                @Override
                public void run() {
                    synchronized (startupShutdownMonitor) {
                        doClose();
                    }
                }
            };
            Runtime.getRuntime().addShutdownHook(this.shutdownHook);
        }
    }

上面代码功能主要是在JVM关闭时调用doClose()方法来完成Spring清理工作,可以查看close()方法,里面工作也是调用doClose()来完成Spring清理工作

/**
     * Close this application context, destroying all beans in its bean factory.
     * <p>Delegates to {@code doClose()} for the actual closing procedure.
     * Also removes a JVM shutdown hook, if registered, as it's not needed anymore.
     * @see #doClose()
     * @see #registerShutdownHook()
     */
    @Override
    public void close() {
        synchronized (this.startupShutdownMonitor) {
            doClose();
            // If we registered a JVM shutdown hook, we don't need it anymore now:
            // We've already explicitly closed the context.
            if (this.shutdownHook != null) {
                try {
                    Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
                }
                catch (IllegalStateException ex) {
                    // ignore - VM is already shutting down
                }
            }
        }
    }

在close()方法中,首先调用doClose()来完成清理工作,在清理完成后删除之前注册的shutdownHook,如果该处不移除钩子则在JVM关闭时会再执行一次清理工作.

  • getBeanFactory() 该方法用来获取内部BeanFactory,具体实现是在AbstractRefreshableApplicationContext中来完成,从AbstractRefreshableApplicationContext源代码可以看出,getBeanFactory()其实返回的是一个DefaultListableBeanFactory对象.另外通过该方法注释可以看出getBeanFactory()仅仅只能在isActive()返回true的时候调用,否则会抛出异常,也就是说在refresh()和close()之间调用,在refresh()之前和close()后调用都会抛出异常.

    AbstractApplicationContext

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean

下面主要看下该类的refresh()实现方法,代码如下:

@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.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

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

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                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();
            }
        }
    }
  • refresh()方法是线程安全的.
  • prepareRefresh()方法主要初始化属性资源并验证系统环境中的属性配置.
  • ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();这里创建了内置BeanFactory, obtainFreshBeanFactory()源码如下:
/**
     * Tell the subclass to refresh the internal bean factory.
     * @return the fresh BeanFactory instance
     * @see #refreshBeanFactory()
     * @see #getBeanFactory()
     */
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

在obtainFreshBeanFactory()方法内部首先调用refreshBeanFactory()方法来初始化配置BeanFactory,该方法在AbstractApplicationContext类中定义为抽象方法,就像注释说明一样该方法在子类中实现.而实现该方法的类为AbstractRefreshableApplicationContext,同样该类实现了上面提到的ConfigurableApplicationContext接口中定义的getBeanFactory()方法,getBeanFactory()返回的既是refreshBeanFactory()方法创建的DefaultListableBeanFactory对象.refreshBeanFactory()方法源代码如下:

/**
     * This implementation performs an actual refresh of this context's underlying
     * bean factory, shutting down the previous bean factory (if any) and
     * initializing a fresh bean factory for the next phase of the context's lifecycle.
     */
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

在该方法中,首先判断当前beanFactory是否存在,如果存在则将之前对象销毁,然后调用createBeanFactory()创建DefaultListableBeanFactory,创建完成之后将当前ApplicationContext的ID赋给该DefaultListableBeanFactory,同时调用loadBeanDefinitions(DefaultListableBeanFactory beanFactory)方法开始真正初始化配置工作,而loadBeanDefinitions方法在AbstractRefreshableApplicationContext类中定义为抽象方法,具体是在XmlWebApplicationContext中实现.

下面返回AbstractApplicationContext类的refresh()方法:

  • prepareBeanFactory(beanFactory);该方法主要用来完成BeanFactory预处理工作.比如设置BeanClassLoader,以及设置BeanExpressionResolver来完成SPEL表达式的处理(即处理bean中的”#{…}”表达式).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值