美文网首页
5. 容器的功能扩展(一)

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

作者: 凭窗听风 | 来源:发表于2019-04-28 00:12 被阅读0次

spring源码学习笔记,要点归纳和代码理解

前言

在前面的学习中,一直以BeanFatory为中心,分析了配置文件的加载、解析过程和BeanFactory对注入对象的创建过程。
Spring提供了另一个接口ApplicationContext接口,它提供了所有BeanFactory的功能,并进一步扩展了作为容器的功能。
本节将跟随源码探究其提供的扩展以及实现原理。

一. ApplicationContext容器的概览和refresh()方法中的行为

  1. 选用XmlApplicationContext作为切入点进行分析。照例看一下继承结构。


debug跟一下构造方法,发现其核心功能全部在AbstractApplicationContextrefresh()方法中.

  1. refresh方法的中的行为
    这里贴出refresh方法的代码
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
            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.
                // 对实现类覆盖的方法做额外处理
                postProcessBeanFactory(beanFactory);

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

                // Register bean processors that intercept bean creation.
                // 注册拦截Bean创建的Bean处理器,这里只进行注册,调用在getBean时
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                // 为上下文环境初始化Message源,国际化处理
                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中的各方法行为解析

  1. 初始化的环境准备: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
        // 校验环境参数
        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()方法可以由子类重写,贴一个简单的应用场景.
假如某工程中需要一个环境变量机房编号roomnumber,此变量缺失将导致工程崩溃,要求缺失此变量时无法启动工程.
我们可以自定义MyClassPathXmlApplicationContext,重写initPropertySources方法,其中加入相关逻辑如下:

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {

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

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

}

则在启动时抛出异常



启动参数中添加-Droomnumber=5,则正常启动


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

protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            // 创建一个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的功能,这里设置了是否允许循环依赖和是否允许方法重写,依旧支持子类重写
如下:

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.
        // 这只几个自动装配的特殊规则
        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.
        // 添加内置的监听器作为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()));
        }
        // 添加几个默认的系统环境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());
        }
    }

这里实现了对原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处理器

小结

本节讲解了ApplicationContext对BeanFactory的功能初始化扩展,对BeanFactory的后处理将在下节继续分析.

相关文章

  • 5. 容器的功能扩展(一)

    spring源码学习笔记,要点归纳和代码理解 前言 在前面的学习中,一直以BeanFatory为中心,分析了配置文...

  • 顺序容器

    所有容器类都有共享公共的接口,不同容器按照不同方式对其进行扩展。每种容器都提供了不同性能和功能的权衡 顺序容器:在...

  • k8s学习笔记(二)k8s的结构和功能

    一、k8s的功能 2014年谷歌开源的容器化集群管理系统,(1)用于容器化应用部署,(2) 利于应用扩展,(3)高...

  • 6. 容器的功能扩展(二)

    spring源码学习笔记,要点归纳和代码理解 前言 上一节讲述了容器初始化过程中beanFactory的创建以及b...

  • Kubernetes三大落地姿势,你pick谁?

    Kubernetes是面向企业的开源容器编排工具的事实标准,它提供了应用部署、扩展、容器管理等功能。经过几年的发展...

  • Jenkins实践指南-09-pipeline 扩展

    5. pipeline 扩展     如果在大量使用pipelin后,会发现Jenkins内置的功能并不能满足我们...

  • SpringBoot2 使用Spring Session集群

    有几种办法: 1.扩展指定server 利用Servlet容器提供的插件功能,自定义HttpSession的创建和...

  • Spring学习笔记(二)后处理器与AOP

    1.后处理器 后处理器是对IOC容器功能的扩展。按我的理解,扩展的原理是在某动作结束后再次调用指定的方法进行扩展处...

  • 一张图看明白Kubernetes架构

    Kubernetes是Google开源的容器集群管理系统,提供应用部署、维护、扩展机制等功能,利用Kubernet...

  • OpenApplus小程序容器

    概述 OpenApp+ 一个小程序容器,配置简单、功能完善、界面流畅、开箱即用!使用OpenApp+可以快速扩展你...

网友评论

      本文标题:5. 容器的功能扩展(一)

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