对于 Spring Boot 应用来说,不管是直接运行调用了 SpringApplication#run(Class, String[]) 的 main 方法来启动 Spring Boot 应用,还是通过传统方式(参见 SpringBootServletInitializer 和 SpringServletContainerInitializer),将应该打包成 war 包放到 Web 容器中去运行,最终都会调用 SpringApplication#run(String...) 方法来启动应用、创建和刷新 ApplicationContext 。
下面先看 SpringApplication#run(String...) 方法:
|
|
上面调用的方法中最重要的是 refreshContext 方法,它最终会调用 AbstractApplicationContext#refresh() 方法,refresh 方法主要完成以下工作:
通过调用
invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory)方法从入口类(即使用@SpringBootApplication注解的类,对于打包成 war 包放到 Web 容器运行的情况,入口类仅仅是个配置类)读取注解,处理@ComponentScan、@Import注解(@SpringBootApplication包含了@ComponentScan注解,也包含了@EanbleAutoConfiguration注解,此注解包含@Import注解), 对前者的处理会扫描并注册所有@Component注解的类的 bean 定义,如果是@Configuration(此注解包含了@Component注解)注解的类,将会递归进行解析(注册其声明的 Bean 的定义);对于@Import注解,会调用注解value对应的类的selectImports方法。对于
@EanbleAutoConfiguration来说, 其@Import注解value对应的类是AutoConfigurationImportSelector,它的selectImports方法会从META-INF/spring.factories加载很多符合条件的自动配置的类,类似于配置类,也会递归解析注册其声明的 Bean 定义。继续执行到
onRefresh()方法,createWebServer()将会被调用:12345678910111213141516171819202122232425262728// ServletWebServerApplicationContext.javaprivate void createWebServer() {WebServer webServer = this.webServer;ServletContext servletContext = getServletContext();// 使用内置容器启动的情况if (webServer == null && servletContext == null) {ServletWebServerFactory factory = getWebServerFactory();// 创建一个 Tomcat 实例并启动,会调用传入的 ServletContainerInitializer 的 onStartup 方// 法,这里 getSelfInitializer() 方法返回的 ServletContainerInitializer 是一个匿名内部// 类,其 onStartup 方法会调用 selfInitialize 方法, selfInitialize 方法会获取所有// ServletContainerInitializer 实例(比如 ServletRegistrationBean 和// FilterRegistrationBean 实例)并调用其 onStartup 方法。对于 ServletRegistrationBean// 和 FilterRegistrationBean 实例 来说,其 onStartup 方法会将对应的 Servlet 和 Filter// 添加到 ServletContext 中。this.webServer = factory.getWebServer(getSelfInitializer());}// 使用外部容器启动的情况else if (servletContext != null) {try {getSelfInitializer().onStartup(servletContext);}catch (ServletException ex) {throw new ApplicationContextException("Cannot initialize servlet context",ex);}}initPropertySources();}DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration#dispatcherServletRegistration()返回的DispatcherServletRegistrationBean包含一个DispatcherServlet实例,在onStartup方法中会被添加到ServletContext中。接下来查找并注册监听器的 Bean 定义,实例化所有未实例化的(non-lazy-init)单例 Bean 。
接着调用
finishRefresh()方法,发布ContextRefreshedEvent事件。这个时候应用内置容器已经启动好了,应用也就运行起来了。