最后更新于
这有帮助吗?
最后更新于
这有帮助吗?
本篇我们解析第9、12、13步骤:
这些方法可以看得出来都属于最终的步骤了,简单扫一眼:
非常简单,不再深入。
可以发现源码中默认使用 DefaultLifecycleProcessor
作为生命周期处理器。它的文档注释原文翻译:
Default implementation of the LifecycleProcessor strategy.
LifecycleProcessor: Strategy interface for processing Lifecycle beans within the ApplicationContext.
用于在 ApplicationContext
中处理 Lifecycle
类型的Bean的策略接口。
从文档注释中又看到了一个新的概念:Lifecycle
。
Lifecycle
是一个接口,它的文档注释原文翻译:
A common interface defining methods for start/stop lifecycle control. The typical use case for this is to control asynchronous processing. NOTE: This interface does not imply specific auto-startup semantics. Consider implementing SmartLifecycle for that purpose. Can be implemented by both components (typically a Spring bean defined in a Spring context) and containers (typically a Spring ApplicationContext itself). Containers will propagate start/stop signals to all components that apply within each container, e.g. for a stop/restart scenario at runtime. Can be used for direct invocations or for management operations via JMX. In the latter case, the org.springframework.jmx.export.MBeanExporter will typically be defined with an org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler, restricting the visibility of activity-controlled components to the Lifecycle interface. Note that the present Lifecycle interface is only supported on top-level singleton beans. On any other component, the Lifecycle interface will remain undetected and hence ignored. Also, note that the extended SmartLifecycle interface provides sophisticated integration with the application context's startup and shutdown phases.
定义启动/停止生命周期控制方法的通用接口。典型的用例是控制异步处理。注意:此接口并不意味着特定的自动启动语义。考虑为此目的实施 SmartLifecycle。
可以通过组件(通常是在Spring上下文中定义的 Spring
bean)和容器(通常是Spring ApplicationContext
本身)实现。容器会将开始/停止信号传播到每个容器中应用的所有组件,例如在运行时停止/重新启动的情况。
可以用于直接调用或通过JMX进行管理操作。在后一种情况下,通常将使用 InterfaceBasedMBeanInfoAssembler
定义 MBeanExporter
,从而将活动控制的组件的可见性限制为 Lifecycle
接口。
请注意,当前的 Lifecycle
接口仅在顶级 Singleton Bean
上受支持。在任何其他组件上,Lifecycle
接口将保持未被检测到并因此被忽略。另外,请注意,扩展的 SmartLifecycle
接口提供了与应用程序上下文的启动和关闭阶段的复杂集成。
到这里我们大概看懂了,实现了 Lifecycle
接口的Bean可以规范化它的生命周期,可以在IOC容器的启动、停止时,自动触发接口中定义的 start
方法和 stop
方法。
Lifecycle
还有一个扩展的接口:SmartLifecycle
,它的文档注释关键部分:
An extension of the Lifecycle interface for those objects that require to be started upon ApplicationContext refresh and/or shutdown in a particular order. The isAutoStartup() return value indicates whether this object should be started at the time of a context refresh. The callback-accepting stop(Runnable) method is useful for objects that have an asynchronous shutdown process. Any implementation of this interface must invoke the callback's run() method upon shutdown completion to avoid unnecessary delays in the overall ApplicationContext shutdown.
Lifecycle
接口的扩展,用于那些需要按特定顺序刷新和/或关闭IOC容器时启动的对象。 isAutoStartup()
返回值指示是否应在刷新上下文时启动此对象。接受回调的 stop(Runnable)
方法对于具有异步关闭过程的对象很有用。此接口的任何实现都必须在关闭完成时调用回调的 run()
方法,以避免在整个IOC容器关闭中不必要的延迟。
从文档注释中可以看到一个很关键的信息:stop(Runnable)
,这就意味着可以在 stop
动作中再注入一些自定义逻辑。从它的方法定义中,可以看到它还扩展了几个方法:
getPhase
- Bean的排序(类似于 @Order
或 Ordered
接口)
isAutoStartup
- 如果该方法返回 false ,则不执行 start 方法。
这两个接口比较简单,不再深入研究,有兴趣的小伙伴可以写几个测试Demo体会一下。
紧接着调用这些 LifecycleProcessor
的 onRefresh
方法。具体到 DefaultLifecycleProcessor
中:
源码也是比较好理解的,它会从IOC容器中找出所有的 Lifecycle
类型的Bean,遍历回调 start
方法。
很明显它发布了 ContextRefreshedEvent
事件,代表IOC容器已经刷新完成。有关事件与监听器的部分,我们在13篇中已经解释过了,不再赘述。
清除缓存也是够简单了,不再深追。
以上就是全部 AbstractApplicationContext
的 refresh 方法了。之前留了一个章节,说 SpringBoot
对 onRefresh
方法有一个扩展,下面咱来看看都扩展了个什么东西:
在第13篇中,我们说在 AbstractApplicationContext
中没有真正实现这个方法,而是留给了子类。SpringBoot 扩展的IOC容器中对这个方法进行了真正地实现:
它要创建一个WebServer:
因为一次创建只能运行在一个 Servlet容器中,说明一次只能取出一个Bean来。
默认的 Tomcat
创建工厂应该从这里取出:TomcatServletWebServerFactory
,他实现了 ServletWebServerFactory
接口。
这个 TomcatServletWebServerFactory
,应该是在自动配置时注册好的。
这个类我们之前看过,它使用 @Import
导入了 ServletWebServerFactoryConfiguration
以及三个内部类:
不难发现,TomcatServletWebServerFactory
在这里被创建。
方法体中第一行:
发现 Tomcat 在此被创建了。
ServletWebServerApplicationContext
还重写了 finishRefresh
方法:
可以发现在此处启动嵌入式Web容器。
这里调用了 WebServer
的start方法真正启动嵌入式Web容器。
嵌入式Tomcat容器的更多原理解读和源码分析,在后面会有专门的篇章来读,此处不作过多解释,只希望小伙伴们知道在这个时机创建的嵌入式Tomcat即可。
空方法,且借助IDEA发现没有子类再实现,故不再深究。
源码很简单,根据前面的部分可得知直接来到 EventPublishingRunListener
:
这部分会回到 AbstractApplicationContext
中:
之后继续往下调:
上面的预处理部分咱们不关心,关键的看这两段if-else:
第一段if-else是在当前IOC容器发布 ApplicationStartedEvent
事件
下面的if结构会向父容器发布 ApplicationStartedEvent
事件
由此可见事件的发布还会影响到父容器。
这部分涉及到两个概念: CommandLineRunner
和 ApplicationRunner
。
文档注释原文翻译:
用于指示bean被包含在 SpringApplication
中时应该运行的接口。可以在同一应用程序上下文中定义多个 CommandLineRunner
Bean,并且可以使用 Ordered
接口或 @Order
注解对其进行排序。
如果需要访问 ApplicationArguments
而不是原始String数组,请考虑使用 ApplicationRunner
。
文档注释原文翻译:
用于指示bean被包含在 SpringApplication
中时应该运行的接口。可以在同一应用程序上下文中定义多个 ApplicationRunner
Bean,并可以使用 Ordered
接口或 @Order
注解对其进行排序。
文档注释都没有明确的对这两个组件有很好的解释。翻看 SpringBoot
的官方文档:
官方文档甚至没有说明这两个接口到底能干什么,只告诉我们怎么用。那这两个组件到底是干什么的呢?
其实这两个接口组件,如果翻看它的文档注释中的since,会发现一个没有标注,一个是 SpringBoot1.3.0
,说明它们都来自于 SpringBoot1.x
。它们本来是用于监听特定的时机来执行一些操作,奈何 SpringBoot2.x
后扩展了事件,可以通过监听 ApplicationStartedEvent
来实现跟这两个组件一样的效果。换句话说,这两个组件已经被隐式的“淘汰”了,不必过多深究。
至此,SpringBoot应用启动成功。
Interface used to indicate that a bean should run when it is contained within a SpringApplication. Multiple CommandLineRunner beans can be defined within the same application context and can be ordered using the Ordered interface or annotation. If you need access to ApplicationArguments instead of the raw String array consider using ApplicationRunner.
Interface used to indicate that a bean should run when it is contained within a SpringApplication. Multiple ApplicationRunner beans can be defined within the same application context and can be ordered using the Ordered interface or annotation.