Spring Boot 基于 SpringApplication 启动时,通过 监听器 监听对应的事件,执行相关的动作。
众所周知,我们可以在 Spring Boot 项目中引入 Spring Cloud 相关依赖。 Spring Cloud 实际上就是 Spring Boot 基于 监听器 拓展的,该监听器就是 Spring Cloud 子项目 spring-cloud-commons 下 spring-cloud-context 模块提供的 BootstrapApplicationListener,配置在spring.factories 文件中由 Spring Boot 应用加载,监听对应的事件后启动 Spring Cloud 容器。
非web环境下,一般来说常用的就两类ApplicationContext:
- 配置形式为XML的:ClassPathXmlApplicationContext、FileSystemXmlApplicationContext。
- 配置形式为注解的:AnnotationConfigApplicationContext。
web环境下默认的上下文ApplicationContext:
- AnnotationConfigServletWebServerApplicationContext:
1、BootstrapApplicationListener
监听器的加载&调用参考。该监听器绑定于SpringCloud微服务的依赖。并且位于SpringBoot中众多应用监听器集合的首位。
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
//StandardServletEnvironment
ConfigurableEnvironment environment = event.getEnvironment();
...
ConfigurableApplicationContext context = bootstrapServiceContext(environment, event.getSpringApplication(),
configName);
...
}
...
private ConfigurableApplicationContext bootstrapServiceContext(
ConfigurableEnvironment environment, final SpringApplication application,
String configName) {
StandardEnvironment bootstrapEnvironment = new StandardEnvironment();
...
SpringApplicationBuilder builder = new SpringApplicationBuilder()
.profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF)
.environment(bootstrapEnvironment)
// Don't use the default properties in this builder
.registerShutdownHook(false).logStartupInfo(false)
.web(WebApplicationType.NONE);
final SpringApplication builderApplication = builder.application();
...
final ConfigurableApplicationContext context = builder.run();
return context;
}
- WebApplicationType.NONE:表示加载的ConfigurableApplicationContext为AnnotationConfigApplicationContext。
- builder.run():重新触发SpringApplication#run方法执行实现容器的刷新。
- 通常情况下AnnotationConfigApplicationContext触发容器刷新之后,会继续生成web环境下上下文之AnnotationConfigServletWebServerApplicationContext并再次刷新容器。
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
switch (this.webApplicationType) {
case SERVLET://AnnotationConfigServletWebServerApplicationContext
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default://AnnotationConfigApplicationContext
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
//通过反射方式实例化对应的ConfigurableApplicationContext
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
AnnotationConfigApplicationContext、AnnotationConfigServletWebServerApplicationContext其共同父类均为GenericWebApplicationContext、BeanDefinitionRegistry。
2、ConfigurableApplicationContext
接口ConfigurableApplicationContext的子类在实例化过程中都会触发其父类GenericWebApplicationContext的实例化。GenericWebApplicationContext实例化都会创建Spring中核心容器DefaultListableBeanFactory
。由此得知ConfigurableApplicationContext的子类拥有独立的IOC容器之DefaultListableBeanFactory。
接口ConfigurableApplicationContext的子类在实例化过程中会触发预发性的PostProcessor
后置处理器作为普通bean注册其定义信息【DefaultListableBeanFactory#registerBeanDefinition
】。主要包括:ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、EventListenerMethodProcessor等最早的后置处理器。
这些后置处理器本身也是普通类,也需要遵循Spring IOC容器中bean的加载过程,即类信息包装为RootBeanDefinition并注册、实例化、初始化等过程。
registerBeanDefinition其实就是将之后bean实例化得到的bean名称以及RootBeanDefinition的对应关系暂时存储在JVM内存中
2.1、AnnotationConfigApplicationContext
public AnnotationConfigApplicationContext() {
//注册当前类的RootBeanDefinition信息以及部分BeanPostProcessor的RootBeanDefinition信息
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
2.3、AnnotationConfigServletWebServerApplicationContext
public AnnotationConfigServletWebServerApplicationContext() {
//注册当前类的RootBeanDefinition信息以及部分BeanPostProcessor的RootBeanDefinition信息
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}