Spring源码学习笔记(3)——容器的功能扩展

120 阅读4分钟

Spring源码学习笔记(3)——容器的功能扩展

一. 引入ApplicationContext接口

  1. 前面的介绍都是基于BeanFactory接口和它的默认实现XmlBeanFactory的,但是Spring体系中还有一个重要的接口:ApplicationContext。ApplicationContext在BeanFactory上进行了一些扩展,功能更为强大。可以理解为:BeanFactory是Spring容器内部使用的,而ApplicationContext是暴露给应用使用的。除非在一些特殊情况下,否则Spring建议使用ApplicationContext接口的实现类。

  2. 示例程序

    以一段几乎每个Java程序员都写过的代码为例:

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    

    ClassPathXmlApplicationContext可以支持多个配置路径,在setConfigLocations()方法中进行处理,后续功能都在refresh()方法中:

    public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
            throws BeansException {
    
        super(parent);
        //设置配置路径
        setConfigLocations(configLocations);
    
        if (refresh) {
            refresh();
        }
    }
    

    下面重点分析refresh()方法。

二. 整体流程

  1. refresh()的实现在AbstractApplicationContext类中,这是ApplicationContext体系中十分重要的一个方法,在整体上定义了ApplicationContext容器的启动流程:

    @Override
    public void refresh() throws BeansException, IllegalStateException {
       synchronized (this.startupShutdownMonitor) {
        //准备带刷新的上下文环境
           prepareRefresh();
    
           //初始化BeanFactory,并读取Spring配置文件
           ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
           //对初始化BeanFactory进行各种功能的填充
           prepareBeanFactory(beanFactory);
    
           try {
               //提供给子类的模板方法,可做额外处理
               postProcessBeanFactory(beanFactory);
    
               //激活容器中注册的处理器,进行各种处理
               invokeBeanFactoryPostProcessors(beanFactory);
    
               //注册BeanPosyProcesor后处理器,拦截Bean的创建过程。这里只是注册,并未执行
               registerBeanPostProcessors(beanFactory);
    
                //为容器初始化各种Message源,即多语言、国际化处理
               initMessageSource();
    
               //初始化消息广播器,将applicationEventMulticaster注册到单例容器中,为容器的消息机制做准备
               initApplicationEventMulticaster();
    
               //提供给子类的模板方法,可初始化其他Bean
               onRefresh();
    
            //在所有注册的Bean中查找Listener Bean,注册到消息广播器applicationEventMulticaster中
               registerListeners();
    
               //初始化剩余的单例Bean(非lazy-init的)
               finishBeanFactoryInitialization(beanFactory);
    
               //最后一步:完成容器刷新过程,通知容器中的LifecycleProcessor刷新完成,并且发布ContextRefreshedEvent容器刷新完成事件
               finishRefresh();
           }
    
           //异常处理
           catch (BeansException ex) {
               if (logger.isWarnEnabled()) {
                   logger.warn("Exception encountered during context initialization - " +
                               "cancelling refresh attempt: " + ex);
               }
    
               destroyBeans();
    
               cancelRefresh(ex);
    
               throw ex;
           }
    
           finally {
               //清空Spring通用缓存
               resetCommonCaches();
           }
       }
    }
    
  2. 可以看到,整个refresh()的流程是很清晰的,处理异常处理外,大概做了这么几件事:

    1. 初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证。

      在某些情况下,项目的运行需要读取某些系统变量,这些变量的设置可能会影响系统的正确性,此时prepareRefresh()这个方法就可以发挥它的作用,在容器启动时(一般也是项目启动时)为我们检查这些变量的设置。

    2. 初始化BeanFactory,并读取XML配置文件

      在这一步中会复用BeanFactory的读取配置文件和加载Bean的过程,在这一步之后,ApplicationContext实际上就包含了所有BeanFactory所提供的功能,可以进行Bean的提取等工作了。

    3. 对BeanFactory进行各种功能的填充

    4. 提供给子类模板方法,做额外的扩展

    5. 激活各种FactoryBean进行处理

    6. 注册BeanPostProcessor后处理器,这里只是注册,真正调用是在getBean()时

    7. 为上下文初始化Message源,处理多语言和国际化

    8. 初始化应用消息广播器ApplicationEventMulticaster,为Spring消息机制做准备

    9. 提供给子类模板方法,初始化其他的Bean

    10. 在所有注册的Bean中查找ApplicationListener,注册到ApplicationEventMulticaster

    11. 初始化其余的非延迟加载的单实例Bean

    12. 完成容器刷新过程,通知LifecycleProcessor,并发布ContextRefreshedEvent容器刷新完成事件

  3. 下面仔细分析具体每一步的处理逻辑

三. 环境准备

  1. 查看方法实现:

    protected void prepareRefresh() {
       this.startupDate = System.currentTimeMillis();
       this.closed.set(false);
       this.active.set(true);
    
       if (logger.isInfoEnabled()) {
           logger.info("Refreshing " + this);
       }
    
       //初始化placeholder属性源,默认空实现,留给子类覆盖
       initPropertySources();
    
       //校验所有需要的属性文件是否都已经放入环境中
       getEnvironment().validateRequiredProperties();
    
       //为early的容器事件做准备
       this.earlyApplicationEvents = new LinkedHashSet<>();
    }
    
  2. 这个方法的核心逻辑默认都是空实现,可以交给子类去覆盖,例如我们可以自定义一个ApplicationContext,并且校验自己的属性文件和系统变量配置

四. 加载BeanFactory

  1. 前面说过,ApplicationContext是对BeanFactory功能上的扩展,不但包含了BeanFactory的全部功能,更是在其基础上添加了大量的扩展应用,obtainFreshBeanFactory()正是实现了BeanFactory的地方,在这个方法之后,ApplicationContext方法就拥有了BeanFactory的全部功能。代码实现:

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
       //初始化BeanFactory,并进行XML文件读取,而且将得到的BeanFactory记录在当前实体的属性中
       refreshBeanFactory();
       ConfigurableListableBeanFactory beanFactory = getBeanFactory();
       if (logger.isDebugEnabled()) {
           logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
       }
       return beanFactory;
    }
    

    核心逻辑委托给了AbstractRefreshableApplicationContext的refreshBeanFactory()方法实现:

    protected final void refreshBeanFactory() throws BeansException {
       if (hasBeanFactory()) {
           destroyBeans();
           closeBeanFactory();
       }
       try {
           //创建DefaultListableBeanFactory
           DefaultListableBeanFactory beanFactory = createBeanFactory();
    
           //指定序列化id,如果需要的话,可以根据序列化id反序列化出BeanFactory对象
           beanFactory.setSerializationId(getId());
    
           //定制BeanFactory相关属性,
           customizeBeanFactory(beanFactory);
    
           //初始化DocumentReader,进行配置文件的读取和解析
           loadBeanDefinitions(beanFactory);
           synchronized (this.beanFactoryMonitor) {
               this.beanFactory = beanFactory;
           }
       }
       catch (IOException ex) {
           throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
       }
    }
    
  2. refreshBeanFactory()的具体步骤:

    1. 创建DefaultListableBeanFactory

      DefaultListableBeanFactory是比较基础的BeanFactory类型。

    2. 设置序列化id。

    3. 定制BeanFactory,是对BeanFactory的扩展,在基本容器的基础上,增加了是否允许覆盖和是否允许循环引用的支持。

    4. 读取配置文件,加载BeanDefinition,该方法交给子类重写,如AbstractXmlApplicationContext类中实现了读取XML文件加载BeanDefinition的处理。

    5. 使用全局变量beanFactory记录BeanFactory实例

五. 对初始化好的BeanFactory进行各种功能的填充

  1. 对于上面初始化好的BeanFactory,进行一些属性的设置和功能上的扩展,具体逻辑在prepareBeanFactory()中:

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       //设置BeanFactory的ClassLoader为当前ApplicationContext的ClassLoader
       beanFactory.setBeanClassLoader(getClassLoader());
    
       //设置BeanFactory的表达式语言处理器,支持表达式语言
       beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    
       //为BeanFactory设置一个默认的PropertyEditor,这个主要是对Bean的属性等设置管理的一个工具
       beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    
       //添加后处理器
       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.registerResolvableDependency(BeanFactory.class, beanFactory);
       beanFactory.registerResolvableDependency(ResourceLoader.class, this);
       beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
       beanFactory.registerResolvableDependency(ApplicationContext.class, this);
    
       beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    
       //增加AspectJ的支持
       if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
           beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
           beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
       }
    
       //注册默认的系统Bean
       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());
       }
    }
    
  2. 该方法主要对BeanFactory进行了以下几个方面的扩展:

    1. 对SPEL表达式的支持
    2. 对属性编辑器的支持
    3. 增加对一些内置类,如EnvironmentAware、MessageSourceAware的信息注入
    4. 对AspectJ的支持

六. BeanFactory的后处理

  1. BeanFactoryPostProcessor

    在BeanFactory的定制化完成之后,开始执行BeanFactory的后处理,后处理主要依赖BeanFactoryPostProcessor类进行。BeanFactoryPostProcessor的功能类似于BeanPostProcessor,可以对Bean的定义(配置元数据)进行处理,也就是说,Spring IoC容器允许BeanFactoryPostProcessor在容器实例化任何其他的Bean之前读取配置元数据,并可能修改它。BeanFactoryPostProcessor与BeanPostProcessor的主要区别在于,BeanFactoryPostProcessor是容器级别的,它的处理依赖于当前的BeanFactory,而且不要通过BeanFactoryPostProcessor进行Bean实例化的相关处理,BeanFactoryPostProcessor只能处理BeanDifinition。

  2. 激活BeanFactoryPostProcessor

    下面回到refresh()方法的处理,调用invokeBeanFactoryPostProcessors()激活容器中注册的BeanFactoryPostProcessor:

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
       PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    
       if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
           beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
           beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
       }
    }
    

    核心方法为PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()),调用容器中所有注册的BeanFactoryPostProcessor的postProcessBeanFactory()方法。

七. 注册BeanPostProcessor

  1. ApplicationContext在registerBeanPostProcessors()方法中注册了BeanPostProcessor,这里只是注册,并不是调用,真正的调用实在创建Bean的时候处理的。这是一个重要的步骤,也是BeanFactory不支持BeanPostProcessor的原因:BeanFactory中没有实现后处理器的自动注册,只能手动注册。

  2. 具体实现:

    public static void registerBeanPostProcessors(
       ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    //获取所有BeanPostProcessor的Bean Name
       String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
    
       //向容器中注册BeanPostProcessorChecker后处理器,只是一个普通的打印
       int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
       beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
    
       //使用priorityOrderedPostProcessors保证顺序
       List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
       List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
    
       //使用orderedPostProcessorNames保证顺序
       List<String> orderedPostProcessorNames = new ArrayList<>();
    
       //无序的BeanPostProcessors
       List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    
    
       for (String ppName : postProcessorNames) {
           if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
               BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
               priorityOrderedPostProcessors.add(pp);
               if (pp instanceof MergedBeanDefinitionPostProcessor) {
                   internalPostProcessors.add(pp);
               }
           }
           else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
               orderedPostProcessorNames.add(ppName);
           }
           else {
               nonOrderedPostProcessorNames.add(ppName);
           }
       }
    
       //1.排序,注册所有实现了PriorityOrdered接口的有序BeanPostProcessor
       sortPostProcessors(priorityOrderedPostProcessors, beanFactory); 
       registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
    
       //2.排序,注册所有实现了Ordered接口的有序BeanPostProcessor
       List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
       for (String ppName : orderedPostProcessorNames) {
           BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
           orderedPostProcessors.add(pp);
           if (pp instanceof MergedBeanDefinitionPostProcessor) {
               internalPostProcessors.add(pp);
           }
       }
       sortPostProcessors(orderedPostProcessors, beanFactory);
       registerBeanPostProcessors(beanFactory, orderedPostProcessors);
    
       //3.注册无序的BeanPostProcessor
       List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
       for (String ppName : nonOrderedPostProcessorNames) {
           BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
           nonOrderedPostProcessors.add(pp);
           if (pp instanceof MergedBeanDefinitionPostProcessor) {
               internalPostProcessors.add(pp);
           }
       }
       registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
    
        //最后,注册实现了MergedBeanDefinitionPostProcessor接口的BeanPostProcessor
       sortPostProcessors(internalPostProcessors, beanFactory);
       registerBeanPostProcessors(beanFactory, internalPostProcessors);
    
       //注册ApplicationListenerDetector探测器
       beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
    }
    

八. 后续步骤

  1. 初始化消息资源

  2. 初始化ApplicationEventMulticaster,为Spring的Event体系提供支持。

    当发布容器事件时,会默认使用SimpleApplicationEventMulticaster对事件进行广播,遍历所有的ApplicationListener,回调ApplicationListener的onApplicationEvent()方法处理事件。每个监听器都可以监听到容器发布的所有事件,但是是否处理由监听器逻辑决定。

  3. 注册监听器

    上面提到的Event体系中的监听器,就是在这里注册的。

  4. 初始化非延迟加载的单例Bean

  5. 容器刷新完成