Spring IOC ApplicationContext的初始化

381 阅读6分钟

作为Spring IOC容器的核心,ApplicationContenxt提供了很多功能接口,这篇文章主要从源码介绍ApplicationContext的初始化过程中做了些什么事情。

其他一些以Spring为基础的框架也大量使用了ApplicationContext的功能,比如Mybatis、Dubbo等,阅读完成,相信你会更容易理解这些框架的工作原理,自己也会写一些通用的框架组件。

入口

ApplicationContext有很多不同的实现,通常继承了AbstractApplicaitonContext:

  1. 或最原始的通过容器web.xml的ContextLoaderListener、通过xml创建ClassPathApplicationContext
  2. 或通过Spring Boot创建 AnnotationConfigServletWebServerApplicationContext

初始化入口,基本都有下面两个过程:

  1. 设置配置元数据类型和路径(xml位置、配置注解类)

    // 设置配置路径,设置配置类等等
    setConfigLocations(configLocations);
    register(annotatedClasses);
    
  2. refresh,进行容器创建、初始化,设置一些功能的处理器等;后面详细介绍

    // 核心方法
    refresh();
    

AbstractApplicaitonContext的refresh方法

BeanFactory创建准备

一些系统属性、环境变量获取,校验

// AbstractApplicaitonContext.refresh
prepareRefresh();

// AbstractApplicaitonContext.prepareRefresh
// 用于环境变量替换placeholder功能
initPropertySources();
getEnvironment().validateRequiredProperties();

BeanFactory对象创建

  1. 创建DefaultListableBeanFactory,作为beanFactory属性放在ApplicationContext中;

(加载bean定义,由具体子类实现(xml/注解))

// AbstractApplicaitonContext.refresh
// 获取BeanFactory,beanFactory作为一个属性被子类持有,两种实现(一个beanFactory只创建一次,一个每次刷新创建)
// 以前会使用,可刷新的实现:AbstractRefreshableApplicationContext,用在外部容器内部,猜想可能是因为外部容器bean生命周期不能由Spring控制,所以每次刷新重新创建一遍
// 但是最新常用的,spring-boot使用的已经是另一个:GenericWebApplicationContext,自己创建容器Server,beanFactory每次刷新只有一个,刷新由SpringBoot启动类控制
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// AbstractApplicaitonContext.obtainFreshBeanFactory
refreshBeanFactory(); // 由两个子类实现

// AbstractRefreshableApplicationContext.refreshBeanFactory
// 加载bean定义,由子类实现,可能为xml形式,可能为注解形式
DefaultListableBeanFactory beanFactory = createBeanFactory();
loadBeanDefinitions(beanFactory);

// GenericWebApplicationContext.refreshBeanFactory 啥也不做,因为只有一个beanFactory,后面会使用别的方式加载beanDefinition,比如BeanFactoryPostProcessor

TODO Spring boot等新型的GenericWebApplicationContext实现如何扫描BeanDefinition的呢?留在BeanDefinition的加载文章中说

BeanFactory功能扩展

准备beanFactory,添加一些特殊bean

添加用于实现一些功能的BeanPostProcessor等,比如:

  1. Spring特殊bean接口相关的回调功能:如ContextAware接口功能、ApplicationListener接口监听事件功能等
// AbstractApplicaitonContext.refresh
prepareBeanFactory(beanFactory);

// AbstractApplicaitonContext.prepareBeanFactory
// SpEl表达式的支持 #{}
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 属性注册编辑器,用于xml设置bean属性时,可以从文本转换为对应需要的类型
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加特殊的BeanPostProcessor,处理一些Aware方法,在后面bean初始化生命周期时机调用,与ApplicationContext有关,区别bean加载调用的beanName,beanFactory等,不同。
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 上面忽略的,对应有直接可注入类型的依赖,其它还有一些
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 处理实现ApplicationListener接口的bean,实现事件发布与订阅,bean初始化生命周期中调用添加/移除listener
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

主要是一些Web的ApplicaitonContext继承使用,添加一些容器相关的如Servlet~Aware接口的bean初始化前调用

BeanFactoryPostProcessor调用

与BeanPostProcessor作用于Bean不同,BeanFactoryPostProcessor作用于BeanDefinition

refresh方法接下来会调用BeanFactoryPostProcessor,传入beanFactory获取到配置元数据,实例化之前可以修改bean定义

典型应用:PropertyPlaceHolderConfigurer,可以使用~ValueResolver结合BeanDefinitionVisitor对BeanDefinition进行修改。

问题:BeanFactoryPostProcessor,其实也是一类特殊的bean,在这一步就被创建完成,调用它的后置处理方法。

// AbstractApplicaitonContext.refresh
// 子类去覆盖实现
postProcessBeanFactory(beanFactory);
// 调用 BeanFactoryPostProcessor beanFactory的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);

// AbstractApplicaitonContext.invokeBeanFactoryPostProcessors
// 调用 BeanFactoryPostProcessors,用来修改BeanDefinition,实现比如使用 properties、enviroment
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

// PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
// 这里会获取到所有 BeanFactoryPostProcessor类型的bean
String[] postProcessorNames =
    beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 直接这时就创建这些bean
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
// 调用这些bean的后置处理方法
postProcessor.postProcessBeanDefinitionRegistry(registry);

BeanPostProcessor的注册

refresh方法的下一步是注册BeanPostProcessor,内部获取并加载BeanPostProcessor类型bean,注册到beanFactory中,真正的调用在bean加载时,实例化之后,属性设置完成,初始化前后。

// AbstractApplicaitonContext.refresh
registerBeanPostProcessors(beanFactory);

// AbstractApplicaitonContext.registerBeanPostProcessors方法
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);

// PostProcessorRegistrationDelegate.registerBeanPostProcessors方法,类似前面BeanFactoryPostProcessor的操作
// 从BeanDefinition中获取 BeanPostProcessor类型的bean名称
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// 直接这时就创建这些bean
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
// 将bean 添加到beanFactory中,后面bean加载时调用,多次add只会改变顺序,不会添加多个
beanFactory.addBeanPostProcessor(postProcessor);

消息及国际化

消息源Bean MessageSource的加载,注册,作用是通过code获取String类型的message,可以根据不同Locale匹配实现国际化

如果用户自定义了,直接加载,如果没有定义,创建默认的,直接注册为单例,不用beanFactory加载。

initMessageSource();

事件发布

加载注册应用消息广播器ApplicationEventMulticaster bean,默认SimpleApplicationEventMulticaster,实现了两个主要接口,分别用来:

  1. 维护listener,add、remove注册事件的监听器
  2. 传播事件,提供multicastEvent方法(默认同步,可以自定义线程池,异步处理消息逻辑)
// AbstractApplicaitonContext.refresh
initApplicationEventMulticaster();

// 如果没自定义,直接使用SimpleApplicationEventMulticaster,可以配置执行器线程池异步发送消息
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);

这里使用了观察者设计模式,发布订阅模式一般具有订阅调度中心,即事件广播者Bean,被组合到ApplicationContext中专门用来完成事件传播功能

// AbstractApplicaitonContext.refresh
// 子类实现,比如Spring Boot的SpringApplication就是用这个onRefresh回调来进行Server容器的创建
onRefresh();

注册ApplicationListener类型bean到事件广播器的一个set中

// AbstractApplicaitonContext.refresh
// 获取所有ApplicationListener类型的bean,注册到ApplicationEventMulticaster的set域中
registerListeners();

Event泛型参数的获取

Spring中要监听某个事件,写一个实现接口ApplicationListener的bean就可以了

public class AnsiOutputApplicationListener
    implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
}

是通过ResolvableType工具类,可以方便的获取某个对象的类所实现的接口的泛型参数

加载非懒单例bean

加载所有非懒加载的bean,包括一些Spring实现功能自带的Bean,和用户定义的非懒加载Bean:

// AbstractApplicaitonContext.refresh
finishBeanFactoryInitialization(beanFactory);

// AbstractApplicaitonContext.finishBeanFactoryInitialization
// 加载converters和formatters
beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
// 加载所有用户定义的非懒加载bean
beanFactory.preInstantiateSingletons();

// DefaultListableBeanFactory.preInstantiateSingletons
getBean(beanName);

加载Bean的过程比较复杂,会单独列出一篇文章。

refresh完成后工作

完成刷新,清除缓存,回调LifecycleProcessor事件方法,ContextRefreshedEvent,加入到LiveBeansView中

// AbstractApplicaitonContext.refresh
finishRefresh();

// AbstractApplicaitonContext.finishRefresh
// 初始化实现Spring生命周期的Bean
initLifecycleProcessor();
// 回调
getLifecycleProcessor().onRefresh();
// 发布事件
publishEvent(new ContextRefreshedEvent(this));

总结

ApplicationContext在实现BeanFactory接口相关的功能时,增加了许多功能,在加载完成BeanDefinition(这里没有涉及)之后,核心的refresh方法主要实现了以下功能:

  • 环境变量、系统属性支持
  • spEl表达式支持、PropertyEditor等文本属性转换支持
  • 添加BeanPostProcessor,用作实现特殊接口Bean的包括各种生命周期方法回调实现
  • BeanFactoryPostProcessor后置处理,修改BeanDefinition,
  • 向容器中添加包括用户定义的BeanPostProcessors
  • 消息和国际化
  • 事件发布广播中心Bean创建
  • 提供生命周期回调功能
  • 加载Bean