本文分析SpringBoot启动过程中的ApplicationPreparedEvent事件,它跟上文的事件ApplicationContextInitializedEvent一样,都是在prepareContext方法中发布的,同样算是对该方法的补充,正常情况下,接收到该事件的监听器一共有四个
ConfigFileApplicationListener
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
}
if (event instanceof ApplicationPreparedEvent) {
this.onApplicationPreparedEvent(event);
}
}
对于当前事件走第二个分支,进入onApplicationPreparedEvent方法
private void onApplicationPreparedEvent(ApplicationEvent event) {
this.logger.switchTo(ConfigFileApplicationListener.class);
this.addPostProcessors(((ApplicationPreparedEvent)event).getApplicationContext());
}
调用addPostProcessors方法向容器中添加了一个BeanFactoryPostProcessor
protected void addPostProcessors(ConfigurableApplicationContext context) {
context.addBeanFactoryPostProcessor(new ConfigFileApplicationListener.PropertySourceOrderingPostProcessor(context));
}
具体类型为其内部类PropertySourceOrderingPostProcessor
private class PropertySourceOrderingPostProcessor implements BeanFactoryPostProcessor, Ordered {
private ConfigurableApplicationContext context;
PropertySourceOrderingPostProcessor(ConfigurableApplicationContext context) {
this.context = context;
}
public int getOrder() {
return -2147483648;
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.reorderSources(this.context.getEnvironment());
}
private void reorderSources(ConfigurableEnvironment environment) {
PropertySource<?> defaultProperties = environment.getPropertySources().remove("defaultProperties");
if (defaultProperties != null) {
environment.getPropertySources().addLast(defaultProperties);
}
}
}
前文介绍过,BeanFactoryPostProcessor类型会在后面Spring容器refresh的过程调用,触发其postProcessBeanFactory方法,在该方法中,先尝试从environment删除名为defaultProperties的PropertySource,如果删除成功的话再把它添加到PropertySource列表的末尾
其实就是对defaultProperties的优先级做一个修正,默认情况下,该PropertySource的优先级应该是最低的,但是在前面提供过很多个扩展点,可以对environment做一些定制以及干预,如果在这个过程中破坏了defaultProperties兜底的特性,就在将来执行BeanFactoryPostProcessor的时候对它做一个调整
LoggingApplicationListener
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartingEvent) {
this.onApplicationStartingEvent((ApplicationStartingEvent)event);
} else if (event instanceof ApplicationEnvironmentPreparedEvent) {
this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
} else if (event instanceof ApplicationPreparedEvent) {
this.onApplicationPreparedEvent((ApplicationPreparedEvent)event);
} else if (event instanceof ContextClosedEvent && ((ContextClosedEvent)event).getApplicationContext().getParent() == null) {
this.onContextClosedEvent();
} else if (event instanceof ApplicationFailedEvent) {
this.onApplicationFailedEvent();
}
}
对于当前事件进入第三个分支,调用onApplicationPreparedEvent方法
private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
ConfigurableListableBeanFactory beanFactory = event.getApplicationContext().getBeanFactory();
if (!beanFactory.containsBean("springBootLoggingSystem")) {
beanFactory.registerSingleton("springBootLoggingSystem", this.loggingSystem);
}
}
这个方法判断容器中是否存在名为springBootLoggingSystem的bean,如果不存在的话,就把自己的loggingSystem作为一个单例bean注册到容器中
这个loggingSystem就是当前项目使用的日志体系,是在之前的事件ApplicationStartingEvent中初始化的
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
this.loggingSystem.beforeInitialize();
}
我们在系列的第三篇文章中已经看过这个过程,就不在赘述了,这里就是把它存到容器的单例池
BackgroundPreinitializer & DelegatingApplicationListener
这两个监听器跟上篇文章完全一样,前者虽然接收了当前事件,但不会做任何处理,后者只是在存在自定义监听器的情况下,将当前事件向自定义监听器传播