5. 容器的功能擴展(一)

spring源碼學習筆記,要點歸納和代碼理解

前言

在前面的學習中,一直以BeanFatory為中心,分析了配置文件的加載、解析過程和BeanFactory對注入對象的創(chuàng)建過程。
Spring提供了另一個接口ApplicationContext接口,它提供了所有BeanFactory的功能,并進一步擴展了作為容器的功能。
本節(jié)將跟隨源碼探究其提供的擴展以及實現(xiàn)原理。

一. ApplicationContext容器的概覽和refresh()方法中的行為

  1. 選用XmlApplicationContext作為切入點進行分析。照例看一下繼承結構。


debug跟一下構造方法,發(fā)現(xiàn)其核心功能全部在AbstractApplicationContextrefresh()方法中.

  1. refresh方法的中的行為
    這里貼出refresh方法的代碼
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            // 準備刷新的上下文環(huán)境
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            // 通知實現(xiàn)類初始化BeanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            // 對BeanFactory的各種功能進行填充
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                // 對實現(xiàn)類覆蓋的方法做額外處理
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                // 激活BeanFactory處理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 注冊攔截Bean創(chuàng)建的Bean處理器,這里只進行注冊,調用在getBean時
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                // 為上下文環(huán)境初始化Message源,國際化處理
                initMessageSource();

                // Initialize event multicaster for this context.
                // 初始化事件廣播器
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                // 留給子類重寫其他需要在刷新上下文環(huán)境時做的
                onRefresh();

                // Check for listener beans and register them.
                // 注冊監(jiān)聽器
                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中的各方法行為解析

  1. 初始化的環(huán)境準備:prepareRefresh
protected void prepareRefresh() {
        // Switch to active.
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);

        // Initialize any placeholder property sources in the context environment.
        // 初始化配置源,子類可重寫此方法
        initPropertySources();

        // Validate that all properties marked as required are resolvable:
        // see ConfigurablePropertyResolver#setRequiredProperties
        // 校驗環(huán)境參數(shù)
        getEnvironment().validateRequiredProperties();

        // Store pre-refresh ApplicationListeners...
        if (this.earlyApplicationListeners == null) {
            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
        }
        else {
            // Reset local application listeners to pre-refresh state.
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

其中的initPropertySources()方法可以由子類重寫,貼一個簡單的應用場景.
假如某工程中需要一個環(huán)境變量機房編號roomnumber,此變量缺失將導致工程崩潰,要求缺失此變量時無法啟動工程.
我們可以自定義MyClassPathXmlApplicationContext,重寫initPropertySources方法,其中加入相關邏輯如下:

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {

    public MyClassPathXmlApplicationContext(String location) {
        super(location);
    }

    @Override
    public void initPropertySources() {
        getEnvironment().setRequiredProperties("roomnumber");
    }

}

則在啟動時拋出異常



啟動參數(shù)中添加-Droomnumber=5,則正常啟動


  1. 加載BeanFactory :obtainFreshBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        // 刷新beanFactory
        refreshBeanFactory();
        return getBeanFactory();
    }

protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            // 創(chuàng)建一個DefaultListableBeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            // 定制beanFactory功能
            customizeBeanFactory(beanFactory);
            // 加載BeanDefinition
            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還是我們之前分析的DefaultListableBeanFactory, 之后客制化BeanFactory的功能,這里設置了是否允許循環(huán)依賴和是否允許方法重寫,依舊支持子類重寫
如下:

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        if (this.allowBeanDefinitionOverriding != null) {
            beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        if (this.allowCircularReferences != null) {
            beanFactory.setAllowCircularReferences(this.allowCircularReferences);
        }
    }

最后加載BeanDefinition,加載仍然使用了XmlBeanDefinitionReader,這里不再貼出代碼

  1. 功能擴展 : prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        beanFactory.setBeanClassLoader(getClassLoader());
        // 添加EL表達式解析器
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        // 添加屬性解析器
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        // Configure the bean factory with context callbacks.
        // 把自己添加為beanPost處理器
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        // 設置幾個忽略自動裝配的接口
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

        // BeanFactory interface not registered as resolvable type in a plain factory.
        // MessageSource registered (and found for autowiring) as a bean.
        // 這只幾個自動裝配的特殊規(guī)則
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // Register early post-processor for detecting inner beans as ApplicationListeners.
        // 添加內置的監(jiān)聽器作為beanPost處理器
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

        // Detect a LoadTimeWeaver and prepare for weaving, if found.
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            // 添加幾個對AspectJ的支持
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // Set a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
        // 添加幾個默認的系統(tǒng)環(huán)境bean
        // Register default environment beans.
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
    }

這里實現(xiàn)了對原BeanFactory功能的幾個擴展:

  • 添加SpEl表達式的支持
  • 增加屬性注冊編輯器
    在Spring 進行DI注入時,對Date對象注入屬性時,無法被識別,可以添加自定義的屬性編輯器:
public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
    }
}

將屬性編輯器注入到容器中:

<bean name="student" class="com.pctf.contextextend.bean.Student">
        <property name="name" value="pctf"></property>
        <property name="birth" value="1900-11-08"></property>
    </bean>



    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        
        <property name="propertyEditorRegistrars">
            <list>
                <bean class="com.pctf.contextextend.propertyeditorregister.DatePropertyEditorRegistrar"></bean>
            </list>
        </property>
    </bean>
  • 添加ApplicationContextAwareProcessor處理器

小結

本節(jié)講解了ApplicationContext對BeanFactory的功能初始化擴展,對BeanFactory的后處理將在下節(jié)繼續(xù)分析.

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容