springboot启动通过main方法
示例代码
启动类CmsNewApplication.class
@SpringBootApplication
public class CmsNewApplication{
public static void main(String[] args) {
SpringApplication.run(CmsNewApplication.class, args);
}
}
debug流程
SpringApplication#run(Class<?>, String...)
把CmsNewApplication.class传入到变量primarySource
image.png
SpringApplication#run(Class<?>[], String[])
image.png
首先通过new SpringApplication创建类,传入的参数是CmsNewApplication类。然后再调用run方法
创建SpringApplication类
创建SpringApplication类,主要是对resourceLoader、primarySources、webApplicationType、mainApplicationClass变量进行赋值。并添加初始化类和监听器
变量赋值
SpringApplication#SpringApplication(java.lang.Class<?>...)
SpringApplication类的构造方法
image.png
SpringApplication#SpringApplication(ResourceLoader, Class<?>...)
image.png
①、resourceLoader=null,
②、primarySources等于传入的CmsNewApplication类。
③、webApplicationType
调用deduceFromClasspath()方法对webApplicationType赋值
WebApplicationType#deduceFromClasspath
image.png
执行逻辑:首先判断是否含有reactive的DispatcherHandler类并且不含有servlet的DispatcherServlet并且不含有jersey的ServletContainer,如果成立则会返回REACTIVE常量。
对javax.servlet.Servlet和ConfigurableWebApplicationContext进行遍历,如果不包含任意一个则返回NONE。否则都含有则返回WebApplicationType.SERVLET类型。并对webApplicationType赋值等于SERVLET
④、mainApplicationClass
mainApplicationClass通过deduceMainApplicationClass()方法获取
image.png
主要通过得到调用链查找main方法得到所在类(就是得到debug调用链)
添加初始化类和监听器
image.pngimage.png
与启动有关的类是DelegatingApplicationContextInitializer和RestartApplicationListener
调用SpringApplication的run方法
创建SpringApplication(spring应用类)完成,继续调用run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
1、StopWatch 简单秒表类,通过start()和stop()方法进行计时
2、创建ConfigurableApplicationContext类并赋值为null,并创建异常SpringBootExceptionReporter类的集合,并设置Headless配置
3、获取SpringApplicationRunListeners类,这个是spring应用运行监听器类,在spring容器中获取。这里获取只有一个EventPublishingRunListener
image.png
这个类的结构是
image.png
当创建这个类时,会创建默认的initialMulticaster类SimpleApplicationEventMulticaster,并把所有监听器加入到事件广播器属性defaultRetriever之中
4、监听器EventPublishingRunListener类调用starting()开始运行
SpringApplicationRunListeners#starting类实际调用到实现类EventPublishingRunListener#starting方法
image.png
调用事件广播器发布ApplicationStartingEvent(应用开始)事件
SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent)
image.png
SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent, ResolvableType)
image.png
这个方法获取事件类型,是否有多线程执行器Executor,如果包含则后台执行
如果想要添加只需要@Bean("applicationEventMulticaster"),必须是这个beanName
@Bean("applicationEventMulticaster")
public SimpleApplicationEventMulticaster simpleApplicationEventMulticaster(BeanFactory beanFactory,ThreadPoolTaskExecutor poolTaskExecutor){
SimpleApplicationEventMulticaster simpleApplicationEventMulticaster
= new SimpleApplicationEventMulticaster(beanFactory);
simpleApplicationEventMulticaster.setTaskExecutor(poolTaskExecutor);
return simpleApplicationEventMulticaster;
}
@Bean
public ThreadPoolTaskExecutor poolTaskExecutor(){
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setMaxPoolSize(15);
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setQueueCapacity(30);
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
SimpleApplicationEventMulticaster#invokeListener
image.png
SimpleApplicationEventMulticaster#doInvokeListener
image.png
RestartApplicationListener#onApplicationEvent
image.png
5、初始化applicationArguments应用参数及ConfigurableEnvironment配置环境,配置忽略的bean信息。输出Banner图《Spring》
image.png
6、创建应用上下文createApplicationContext()
image.png
根据webApplicationType变量值,创建AnnotationConfigServletWebServerApplicationContext类,并封装成ConfigurableApplicationContext类返回并赋值给context
如果是REACTIVE则创建AnnotationConfigReactiveWebServerApplicationContext类
默认创建AnnotationConfigApplicationContext类
7、获取SpringBootExceptionReporter异常类型exceptionReporters的集合
image.png
8、准备spring上下文环境prepareContext()
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
①、首先为上下文设置环境environment
②、添加ConversionService
bean工厂设置添加ApplicationConversionService
③、调用ApplicationContextInitializer子类初始化一些类到spring容器
④、调用监听器的准备上下文环境contextPrepared()方法
EventPublishingRunListener#contextPrepared发布ApplicationContextInitializedEvent应用环境初始化事件
image.png
这里调用三个监听器对环境没有任何变化
DelegatingApplicationListener、BackgroundPreinitializer、RestartApplicationListener
⑤、 调用活跃的配置信息logStartupProfileInfo(context)
⑥、beanFactory的获取和注册其他单例类
⑦、获取primarySources资源文件(main所在的类)并加载
image.png
注册到AnnotatedBeanDefinitionReader
image.png
⑧、监听器加载环境SpringApplicationRunListeners#contextLoaded
把监听器加入到spring上下文环境中,并发布ApplicationPreparedEvent事件
image.png
RestartApplicationListener、ConfigFileApplicationListener为bean工厂环境添加类
9、刷新上下文环境refreshContext(context)
image.png
SpringApplication#refresh
image.png
ServletWebServerApplicationContext#refresh
image.png
最终调用到AbstractApplicationContext#refresh
与通过注解加载spring环境一样调用加载过程,执行invokeBeanFactoryPostProcessors()执行bean工厂后置处理器,注册bean后置处理器,注册监听器,实例化bean等过程
image.png
①、在实例化initApplicationEventMulticaster方法中
查看bean工厂是否包含beanName是applicationEventMulticaster的ApplicationEventMulticaster类的bean,
解释了在添加为事件广播器添加多线程为什么@Bean需要beanName
image.png
②、onRefresh()方法createWebServer 创建web服务
具体调用AbstractApplicationContext#onRefresh的实现类
image.png
ServletWebServerApplicationContext#onRefresh
image.png
ServletWebServerApplicationContext#createWebServer
image.png
当webServer和servletContext都是null时,将会从bean工厂获取类型是ServletWebServerFactory的web服务工厂类
ServletWebServerApplicationContext#getWebServerFactory
image.png
factory.getWebServer()方法首先获取web服务,然后再调用getSelfInitializer方法
①、获取web服务
TomcatServletWebServerFactory#getWebServer
image.png
TomcatServletWebServerFactory#getTomcatWebServer
image.png
image.png
TomcatWebServer#initialize
image.png
②、getSelfInitializer调用
ServletWebServerApplicationContext#getSelfInitializer
image.png
ServletWebServerApplicationContext#prepareWebApplicationContext
主要是xx.ROOT属性及设置servletContext变量值
image.png
image.png
registerApplicationScope注册servletContext到beanFactory
image.png
ServletContextInitializer调用onStartup方法
image.png
对DispatcherServletRegistrationBean和FilterRegistrationBean初始值设置
调用到this.tomcat.start()之后,会调用getSelfInitializer()方法。启动tomcat
启动之后继续调用TomcatWebServer#initialize方法内start之后的代码
TomcatWebServer#startDaemonAwaitThread
tomcat的设置非守护线程,进入线程后台await状态
image.png
如果servletContext已经有值则直接调用getSelfInitializer().onStartup(servletContext);初始化
10、刷新之后afterRefresh(),空实现。之后停止计时
11、调用callRunners方法
image.png
runSqlScript方法,执行数据库相关命令参数
监听器的使用
1、ApplicationStartingEvent事件
listeners.starting()发布将要开始运行事件ApplicationStartingEvent
有以下默认监听器:
RestartApplicationListener、LoggingApplicationListener、BackgroundPreinitializer、
DelegatingApplicationListener、LiquibaseServiceLocatorApplicationListener
2、ApplicationStartedEvent事件
listeners.started(context)发布开始结束事件ApplicationStartedEvent
有以下默认监听器:
DelegatingApplicationListener、BackgroundPreinitializer、RestartApplicationListener
3、ApplicationReadyEvent事件
listeners.running(context)发布正在运行事件ApplicationReadyEvent
有以下默认监听器:没有实际效果
RestartApplicationListener、SpringApplicationAdminMXBeanRegistrar、BackgroundPreinitializer、DelegatingApplicationListener、ConditionEvaluationDeltaLoggingListener
onApplicationEvent
对发布的事件调用对应的监听器的onApplicationEvent方法
如:RestartApplicationListener#onApplicationEvent
image.png
总结:
springboot启动流程关键就是在什么时机进行刷新spring上下文环境即是调用refresh方法
在刷新过程中创建怎么样的ServletWebServerFactory环境
getWebServer方法创建tomcat环境,并启动tomcat
在启动过程中监听器设计模式的应用及监听器调用时机
创建SpringApplication类对变量的赋值
添加执行线程后台运行监听器方法
网友评论