springboot启动流程,手把手打断点一步步看运行步骤
目錄
一、讓我們從啟動類打斷點一點點剖析啟動過程
二、創建 SpringApplication
1.new SpringApplication
2.初始化參數
(1)獲取bootstrappers:初始啟動引導器
(2)獲取ApplicationContextInitializer初始化器
(3)獲取ApplicationListener?應用監聽器
三、運行 SpringApplication
1.進入run方法
(1)創建引導上下文(Context環境)
(2)bootstrapper其實是個接口
(3)獲取所有 RunListener(運行監聽器)
?(4)準備運行時環境
(5)創建IOC容器
(6)準備ApplicationContext IOC容器的基本信息
(7)IOC容器的經典初始化過程
(8)調用所有runners
一、讓我們從啟動類打斷點一點點剖析啟動過程
public static void main(String[] args) {SpringApplication.run(WebApplicationCxf.class, args); }二、創建 SpringApplication
1.new SpringApplication
// org.springframework.context.ConfigurableApplicationContext public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args); }2.初始化參數
// org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...) public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;// 資源加載器Assert.notNull(primarySources, "PrimarySources must not be null");// 斷言,判斷是否有主配置類this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// 主配置類信息保存起來(標注@SpringBootApplication的)this.webApplicationType = WebApplicationType.deduceFromClasspath();// 判斷web應用的類型(判斷是響應式還是原生的servlet工程)// bootstrappers:初始啟動引導器(List<Bootstrapper>):去spring.factories文件中找 org.springframework.boot.Bootstrapperthis.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));// 找 ApplicationContextInitializer初始化器;去spring.factories找 ApplicationContextInitializer// 存放在List<ApplicationContextInitializer<?>> initializers中,總共7個setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 找 ApplicationListener ;應用監聽器。去spring.factories找 ApplicationListener// 存放在List<ApplicationListener<?>> listeners中,總共9個setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 決定誰是主程序,有main方法的類就是主程序this.mainApplicationClass = deduceMainApplicationClass(); }(1)獲取bootstrappers:初始啟動引導器
// org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[], java.lang.Object...) private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicates// 去spring.factories文件中找 org.springframework.boot.BootstrapperSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances; }(2)獲取ApplicationContextInitializer初始化器
都是從spring.factories文件中查找 ApplicationContextInitializer,可能不僅局限于一個spring.factories文件
?
?
(3)獲取ApplicationListener?應用監聽器
都是從spring.factories文件中查找ApplicationListener?,可能不僅局限于一個spring.factories文件
?
三、運行 SpringApplication
1.進入run方法
// org.springframework.context.ConfigurableApplicationContext public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args); } // org.springframework.boot.SpringApplication#run(java.lang.String...) public ConfigurableApplicationContext run(String... args) {// 應用停止監聽器StopWatch stopWatch = new StopWatch();stopWatch.start(); // 記錄應用的啟動時間// 創建引導上下文(Context環境)createBootstrapContext()DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;// 設置headless屬性方法(java.awt.headless),讓當前應用進入headless模式(自力更生模式,詳情自行百度)configureHeadlessProperty();//獲取所有 RunListener(運行監聽器)【為了方便所有Listener進行事件感知】SpringApplicationRunListeners listeners = getRunListeners(args);// 遍歷 SpringApplicationRunListener 調用 starting 方法,相當于通知所有對系統正在啟動過程感興趣的人,項目正在 starting。listeners.starting(bootstrapContext, this.mainApplicationClass);try {// 保存命令行參數;ApplicationArgumentsApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 準備運行時環境ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);// 打印bannerBanner printedBanner = printBanner(environment);// 創建IOC容器// 根據項目類型(Servlet)創建容器,當前會創建 AnnotationConfigServletWebServerApplicationContextcontext = createApplicationContext();context.setApplicationStartup(this.applicationStartup);// 準備ApplicationContext IOC容器的基本信息prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 刷新IOC容器,調用IOC容器的經典初始化過程,創建容器中的所有組件refreshContext(context);// 容器刷新完成后工作,方法是空的afterRefresh(context, applicationArguments);// 監控花費的時間stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}// 所有監聽器 調用 listeners.started(context); 通知所有的監聽器 startedlisteners.started(context);// 調用所有runnerscallRunners(context, applicationArguments);}// 如果有異常,調用Listener 的 failed方法catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {// 調用所有監聽器的 running 方法 listeners.running(context); 通知所有的監聽器 runninglisteners.running(context);}// running如果有問題。繼續通知 failed 。調用所有 Listener 的 failed;通知所有的監聽器 failedcatch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context; }(1)創建引導上下文(Context環境)
private DefaultBootstrapContext createBootstrapContext() {DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); // 創建默認的引導上下文// 獲取到所有之前的 bootstrappers 挨個執行 intitialize() 來完成對引導啟動器上下文環境設置this.bootstrappers.forEach((initializer) -> initializer.intitialize(bootstrapContext));return bootstrapContext; }(2)bootstrapper其實是個接口
public interface Bootstrapper {/*** Initialize the given {@link BootstrapRegistry} with any required registrations.* @param registry the registry to initialize*/void intitialize(BootstrapRegistry registry); }(3)獲取所有 RunListener(運行監聽器)
還是去從spring.factories文件中查找SpringApplicationRunListener。
private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };return new SpringApplicationRunListeners(logger,getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),this.applicationStartup); }找到一個listener:
Listener實際是個接口,有如下方法:
?
?(4)準備運行時環境
// org.springframework.boot.SpringApplication#prepareEnvironment private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {// Create and configure the environment// 返回或者創建基礎環境信息對象。StandardServletEnvironmentConfigurableEnvironment environment = getOrCreateEnvironment();// 配置環境信息,通過命令行參數或者配置文件獲取配置屬性值configureEnvironment(environment, applicationArguments.getSourceArgs());// 綁定環境信息ConfigurationPropertySources.attach(environment);// 所有監聽器遍歷調用 listener.environmentPrepared();通知所有的監聽器當前環境準備完成listeners.environmentPrepared(bootstrapContext, environment);DefaultPropertiesPropertySource.moveToEnd(environment);// 激活額外的環境configureAdditionalProfiles(environment);// 綁定一些值bindToSpringApplication(environment);if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment; }(5)創建IOC容器
// org.springframework.boot.SpringApplication#createApplicationContext protected ConfigurableApplicationContext createApplicationContext() {// 根據項目類型(Servlet)創建容器,當前會創建 AnnotationConfigServletWebServerApplicationContextreturn this.applicationContextFactory.create(this.webApplicationType); }(6)準備ApplicationContext IOC容器的基本信息
// org.springframework.boot.SpringApplication#prepareContext private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {// 保存基礎環境信息context.setEnvironment(environment);// IOC容器的后置處理流程(注冊一些組件、讀取配置文件資源、注冊資源加載器、準備類型轉換器等等)postProcessApplicationContext(context);// 應用初始化器:applyInitializers// 遍歷所有的 ApplicationContextInitializer 。調用 initialize方法。來對ioc容器進行初始化擴展功能applyInitializers(context);// 遍歷所有的 listener 調用 contextPrepared方法。listeners.contextPrepared(context);bootstrapContext.close(context);if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beansConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// Load the sourcesSet<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));// 所有的監聽器 調用 contextLoaded。通知所有的監聽器 contextLoadedlisteners.contextLoaded(context); }(7)IOC容器的經典初始化過程
spring容器創建流程參考博文
spring系列-注解驅動原理及源碼-spring容器創建流程-CSDN博客
注意:
spring默認的onRefresh()方法是空的,springboot將onRefresh()方法重寫,加入了tomcat的啟動。
// org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh protected void onRefresh() {super.onRefresh();try {// 創建一個web應用createWebServer();}catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);} }springboot嵌入式tomcat啟動原理參考博文:
https://blog.csdn.net/A_art_xiang/article/details/122435665
(8)調用所有runners
默認是沒有runner。
// org.springframework.boot.SpringApplication#callRunners private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList<>();// 獲取容器中的 ApplicationRunnerrunners.addAll(context.getBeansOfType(ApplicationRunner.class).values());// 獲取容器中的 CommandLineRunnerrunners.addAll(context.getBeansOfType(CommandLineRunner.class).values());// 合并所有runner并且按照@Order進行排序AnnotationAwareOrderComparator.sort(runners);// 遍歷所有的runner。調用 run 方法for (Object runner : new LinkedHashSet<>(runners)) {if (runner instanceof ApplicationRunner) {callRunner((ApplicationRunner) runner, args);}if (runner instanceof CommandLineRunner) {callRunner((CommandLineRunner) runner, args);}} }runner是一個接口:
@FunctionalInterface public interface ApplicationRunner {/*** Callback used to run the bean.* @param args incoming application arguments* @throws Exception on error*/void run(ApplicationArguments args) throws Exception; }總結
以上是生活随笔為你收集整理的springboot启动流程,手把手打断点一步步看运行步骤的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM常用启动参数大全(附带解释)
- 下一篇: 详解sentinel:分布式系统的流量防