赞
踩
本文将以SpringApplication的启动流程以及生命周期各时期发出的Event事件为主线,结合每个生命周期内完成的事件介绍,真正实现一文让你总览Spring Boot的全貌,这对读者深入理解Spring Boot,以及整合进Spring Cloud都将非常重要。
接下来我们先看下SpringApplication生命周期事件流程图,然后再讲解各个事件的详情:
它是和SpringApplication生命周期有关的所有事件的父类,@since 1.0.0
public abstract class SpringApplicationEvent extends ApplicationEvent {
private final String[] args;
public SpringApplicationEvent(SpringApplication application, String[] args) {
super(application);
this.args = args;
}
public SpringApplication getSpringApplication() {
return (SpringApplication) getSource();
}
public final String[] getArgs() {
return this.args;
}
}
它是抽象类,扩展自Spring Framwork的ApplicationEvent,确保了事件和应用实体SpringApplication产生关联,它有如下子类,每个事件都代表着SpringApplication不同生命周期所处的位置:
调用getRunListeners()方法, 实例化一个SpringApplicationRunListeners对象, SpringApplicationRunListeners的构造参数通过getSpringFactoriesInstances()方法获得,这个方法获取的一个EventPublishingRunListener对象, 所以调用的是EventPublishingRunListener#starting()方法
ApplicationStartingEvent构造方法中传递了一个SpringApplication对象和args参数。一直传递到了父类EventObject,将SpringApplication对象存放在source变量中。
public class SpringApplication { //run方法 public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); //本文分析的重点,发布启动事件ApplicationStartingEvent //获取SpringApplicationRunListener的子类listener SpringApplicationRunListeners listeners = getRunListeners(args); //执行其starting()方法 listeners.starting(); .... } //获取SpringApplicationRunListener的子类listener private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; //调用getSpringFactoriesInstances方法 //获取SpringApplicationRunListener的子类 //子类只有一个,EventPublishingRunListener //实例化了一个SpringApplicationRunListeners对象 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); } }
SpringApplicationRunListeners是一个比较重要的类, 之后的代码会经常调用这个方法, 内部封装了一个SpringApplicationRunListener的list, 方便以后扩展, 目前只有一个EventPublishingRunListener实例, 所以spring的事件都是由EventPublishingRunListener发布的:
//SpringApplicationRunListeners部分源码 class SpringApplicationRunListeners { private final Log log; //SpringApplicationRunListener的子类对象列表 //listener列表扩展点 private final List<SpringApplicationRunListener> listeners; SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) { this.log = log; this.listeners = new ArrayList<>(listeners); } //发布启动事件 public void starting() { for (SpringApplicationRunListener listener : this.listeners) { //目前调用EventPublishingRunListener#starting方法 listener.starting(); } } //其他事件都是相同的代码 //.... }
EventPublishingRunListener是springboot的事件广播器, 内部封装了一个SimpleApplicationEventMulticaster对象, 用来发布springboot加载过程中的各个事件
//EventPublishingRunListener部分源码 public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { //SpringApplication对象 private final SpringApplication application; //命令函参数 private final String[] args; //事件广播器 private final SimpleApplicationEventMulticaster initialMulticaster; public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; this.initialMulticaster = new SimpleApplicationEventMulticaster(); // 通过application.getListeners(),获取到Listener列表 // ConfigFileApplicationListener // AnsiOutputApplicationListener // LoggingApplicationListener // ClasspathLoggingApplicationListener // BackgroundPreinitializer // DelegatingApplicationListener // ParentContextCloserApplicationListener // ClearCachesApplicationListener // FileEncodingApplicationListener // LiquibaseServiceLocatorApplicationListener for (ApplicationListener<?> listener : application.getListeners()) { //将listener添加到事件广播器initialMulticaster this.initialMulticaster.addApplicationListener(listener); } } @Override public void starting() { // 广播器广播ApplicationStartingEvent事件 this.initialMulticaster.multicastEvent( new ApplicationStartingEvent(this.application, this.args)); } //其他事件发布都是相同的代码 //... }
springboot默认事件广播器, 有三个重要方法, 用于发布spring启动过程中的各个事件:
父类AbstractApplicationEventMulticaster,封装了四个重要方法:
以下是父类AbstractApplicationEventMulticaster源码分析:
//抽象事件广播器 public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware { //监听器遍历器 //成员变量applicationListeners Set维护了application中包含的listeners, //成员变量applicationListenerBeans Set维护了注入的listener bean名称 private final ListenerRetriever defaultRetriever = new ListenerRetriever(false); //调用getApplicationListeners()方法之后 //缓存spring事件以及对应的listener列表 final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64); private Object retrievalMutex = this.defaultRetriever; @Override public void addApplicationListener(ApplicationListener<?> listener) { synchronized (this.retrievalMutex) { //监听器已经被加载过, //先执行删除操作,防止重复执行 Object singletonTarget = AopProxyUtils.getSingletonTarget(listener); if (singletonTarget instanceof ApplicationListener) { this.defaultRetriever.applicationListeners.remove(singletonTarget); } this.defaultRetriever.applicationListeners.add(listener); //清空缓存 this.retrieverCache.clear(); } } /** * 获取支持监听event的listener * 这里使用了单例模式 */ protected Collection<ApplicationListener<?>> getApplicationListeners( ApplicationEvent event, ResolvableType eventType) { Object source = event.getSource(); Class<?> sourceType = (source != null ? source.getClass() : null); ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType); //尝试从ConcurrentHashMap缓存中取出listener列表 ListenerRetriever retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { //双重检查锁定 //当多线程访问的时候, //之前retriever多个线程否返回null, //此时锁住this.retrievalMutex //防止多次实例化 synchronized (this.retrievalMutex) { //再尝试从cache中获取 retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } //生成Key和Value放入缓存中 retriever = new ListenerRetriever(true); Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType, retriever); this.retrieverCache.put(cacheKey, retriever); return listeners; } } else { //没有缓存ListenerRetriever,那么就不需要同步 return retrieveApplicationListeners(eventType, sourceType, null); } } //retrieveApplicationListeners方法中 //调用了supportsEvent方法 //supportsEvent使用了适配器模式 protected boolean supportsEvent( ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) { GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ? (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener)); return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType)); } }
SimpleApplicationEventMulticaster源码分析:
广播事件, 然后实现每个listener的onApplicationEvent()方法
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster { @Nullable private Executor taskExecutor; @Nullable private ErrorHandler errorHandler; /** * 构造函数 * taskExecutor和errorHandler都是null */ public SimpleApplicationEventMulticaster() { } /** * 广播事件 * @param event 事件 * @param eventType 事件类型 */ @Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); //调用父类getApplicationListeners方法 //遍历所有支持ApplicationStartingEvent事件的监听器 //LoggingApplicationListener //BackgroundPreinitializer //DelegatingApplicationListener //LiquibaseServiceLocatorApplicationListener for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { //此时的executor为null Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { //调用listener invokeListener(listener, event); } } } /** * 具体调用监听器的方法 * @param listener 监听器 * @param event 事件 */ private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { //调用listener的onApplicationEvent方法 listener.onApplicationEvent(event); } catch (ClassCastException ex) { String msg = ex.getMessage(); if (msg == null || matchesClassCastMessage(msg, event.getClass())) { Log logger = LogFactory.getLog(getClass()); if (logger.isDebugEnabled()) { logger.debug("Non-matching event type for listener: " + listener, ex); } } else { throw ex; } } } }
默认情况下,有4个监听器监听ApplicationStartingEvent事件:
总结:此事件节点结束时,SpringApplication完成了一些实例化相关的动作:本实例实例化、本实例属性赋值、日志系统实例化等。
@since 1.0.0。该事件节点是最为重要的一个节点之一,因为对于Spring应用来说,环境抽象Enviroment简直太重要了,它是最为基础的元数据,决定着程序的构建和走向,所以构建的时机是比较早的。
完成的事件内容:
监听此事件的监听器:
默认情况下,有9个监听器监听ApplicationEnvironmentPreparedEvent事件:
BootstrapApplicationListener:来自SpringCloud。优先级最高,用于启动/创建Spring Cloud的应用上下文。需要注意的是:到此时SB的上下文ApplicationContext还并没有创建哦。这个流程“嵌套”特别像Bean初始化流程:初始化Bean A时,遇到了Bean B,就需要先去完成Bean B的初始化,再回头来继续完成Bean A的步骤。
说明:在创建SC的应用的时候,使用的也是SpringApplication#run()完成的(非web),因此也会走下一整套SpringApplication的生命周期逻辑,所以务必区分。特别是这种case会让“绝大多数”初始化器、监听器等执行多次,若你有那种只需要执行一次的需求(比如只想让SB容器生命周期内执行,SC生命周期不执行),请务必自行处理,否则会被执行多次而带来不可预知的结果;SC应用上下文读取的外部化配置文件名默认是:bootstrap,使用的也是ConfigFileApplicationListener完成的加载/解析;
LoggingSystemShutdownListener:来自SpringCloud。对LogbackLoggingSystem先清理,再重新初始化一次,效果同上个事件,相当于重新来了一次,毕竟现在有Enviroment环境;
ConfigFileApplicationListener:@since 1.0.0。它也许是最重要的一个监听器。做了如下事情:
AnsiOutputApplicationListener:@since 1.2.0。让你的终端(可以是控制台、可以是日志文件)支持Ansi彩色输出,使其更具可读性。当然前提是你的终端支持ANSI显示。参考类:AnsiOutput。你可通过spring.output.ansi.enabled = xxx配置,可选值是:DETECT/ALWAYS/NEVER,一般不动即可。另外,针对控制台可以单独配置:spring.output.ansi.console-available = true/false
LoggingApplicationListener:@since 2.0.0。根据Enviroment环境完成initialize()初始化动作:日志等级、日志格式模版等;
值得注意的是:它这步相当于在ApplicationStartingEvent事件基础上进一步完成了初始化(上一步只是实例化);
ClasspathLoggingApplicationListener:@since 2.0.0。用于把classpath路径以log.debug()输出;
值得注意的是:classpath类路径是有N多个的Arrays.toString(((URLClassLoader) classLoader).getURLs()),也就是说每个.jar里都属于classpath的范畴;
BackgroundPreinitializer:本事件达到时无动作;
DelegatingApplicationListener:执行通过外部化配置context.listener.classes = xxx,xxx的监听器们,然后把该事件广播给他们,执行监听此事件的监听器;
这麽做的好处:可以通过属性文件外部化配置监听器,而不一定必须写在spring.factories里,更具弹性;
FileEncodingApplicationListener:检测当前系统环境的file.encoding和spring.mandatory-file-encoding设置的值是否一样,如果不一样则抛出异常如果不配置spring.mandatory-file-encoding则不检查;
总结:此事件节点结束时,Spring Boot的环境抽象Enviroment已经准备完毕,但此时其上下文ApplicationContext还没有创建,但是Spring Cloud的应用上下文(引导上下文)已经全部初始化完毕哦,所以SC管理的外部化配置也应该都进入到了SB里面。如下图所示(这是基本上算是Enviroment的最终态了):
@since 2.1.0,非常新的一个事件。当SpringApplication的上下文ApplicationContext准备好后,对单例Bean们实例化之前,发送此事件。所以此事件又可称为:contextPrepared事件。
完成的事件内容:
上下文实例已经有了,那么就开始对它进行一些参数的设置:
总结:此事件节点结束时,完成了应用上下文ApplicationContext的准备工作,并且执行所有注册的上下文初始化器ApplicationContextInitializer。但是此时,单例Bean是仍旧还没有初始化,并且WebServer也还没有启动;
@since 1.0.0。截止到上个事件ApplicationContextInitializedEvent,应用上下文ApplicationContext充其量叫实例化好了,但是还剩下很重要的事没做,便是此事件的执行内容了;
完成的事件内容:
总结:此事件节点结束时,应用上下文ApplicationContext初始化完成,该赋值的赋值了,Bean定义信息也已全部加载完成。但是,单例Bean还没有被实例化,web容器依旧还没启动。
@since 2.0.0。截止到此,应用已经准备就绪,并且通过监听器、初始化器等完成了非常多的工作了,但仍旧剩下被认为最为重要的初始化单例Bean动作还没做、web容器(如Tomcat)还没启动,这便是这个周期所要做的事。
完成的事件内容:
监听此事件的监听器:
默认情况下,有3个监听器监听ApplicationStartedEvent事件:
总结:此事件节点结束时,SpringApplication的生命周期到这一步,正常的启动流程就全部完成了。也就说Spring Boot应用可以正常对对外提供服务了。
@since 1.3.0。该事件所处的生命周期可认为基本和ApplicationStartedEvent相同,仅是在其后执行而已,两者中间并无其它特别的动作,但是监听此事件的监听器们还是蛮重要的。
监听此事件的监听器:
默认情况下,有4个监听器监听ApplicationStartedEvent事件:
总结:此事件节点结束时,应用已经完完全全的准备好了,并且也已经完成了相关组件的周知工作。
当SpringApplication在启动时抛出异常:可能是端口绑定、也可能是你自定义的监听器你写了个bug等,就会“可能”发送此事件。
完成的事件内容:
监听此事件的监听器:
默认情况下,有6个监听器监听ApplicationStartedEvent事件:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。