玩转springboot之springboot启动原理
启动原理
注意:使用版本为spring-boot-2.2.2.RELEASE
(图片来源网络,侵删)
springboot启动的入口肯定是main方法啦,那就从main方法入口走起来看看是如何进行启动的
@SpringBootApplication public class ConsulApp { public static void main(String[] args) { // 调用SpringApplication的静态run方法 SpringApplication.run(ConsulApp.class,args); } }
进入main方法
// 这个primarySources是传入进来的启动类 public static ConfigurableApplicationContext run(Class[] primarySources, String[] args) { // 先实例化SpringApplication return new SpringApplication(primarySources).run(args); }
实例化SpringApplication
// this(null, primarySources) // resourceLoader是null,primarySources是传入进来的启动类 public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); // 使用set进行去重 this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); // 根据classpath中是否存在org.springframework.web.reactive.DispatcherHandler来判断是否为REACTIVE // 根据classpath中是否存在"javax.servlet.Servlet"和"org.springframework.web.context.ConfigurableWebApplicationContext"来判断是否为SERVLET // web应用的类型,是None表示非web项目 SERVLET表示普通的servlet web项目 REACTIVE表示响应式的web项目 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 设置应用上下文初始化器 SpringFactoriesLoader从META-INF/spring.factories加载的,获取 ApplicationContextInitializer 接口的所有配置的类路径名称,并进行实例化 setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 设置监听器 SpringFactoriesLoader从META-INF/spring.factories加载的,获取ApplicationListener接口的所有配置的类路径名称,并进行实例化 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 推断主启动类,通过构造一个运行时异常,再遍历异常栈中的方法名,获取方法名为 main 的栈帧,从来得到入口类的名字再返回该类 this.mainApplicationClass = deduceMainApplicationClass(); }
执行SpringApplication实例的run方法
实例化SpringApplication之后,调用该对象的run方法
- NO1 进行计时,记录整个过程的加载事件
- NO2 初始化应用上下文和异常报告集合,设置headless变量
- NO3 通过SpringFactoriesLoader加载SpringApplicationRunListener监听器,调用starting方法,表示springboot要启动了
- NO4 创建ConfigurableEnvironment,将配置的环境绑定到spring应用中(包括PropertySource和Profile),并调用SpringApplicationRunListener监听器的environmentPrepared方法,应用的environment已经准备完毕
- NO5 Banner打印并创建应用上下文
- NO6 创建应用上下文,根据webApplicationType决定创建不同的上下文
- NO7 准备应用上下文,执行初始化器ApplicationContextInitializer的initialize方法
- NO8 刷新应用上下文
- NO9 计时停止,调用SpringApplicationRunListener监听器的started方法,表示应用上下文已完成
- NO10 执行所有的Runner运行器(ApplicationRunner和CommandLineRunner)
- NO11 调用SpringApplicationRunListener监听器的running方法,表示已经开始运行了
public ConfigurableApplicationContext run(String... args) { // NO1 // 创建计时监控对象,记录整个过程的加载事件 StopWatch stopWatch = new StopWatch(); // 启动计时监控,记录开始时间 stopWatch.start(); // NO2 // 初始化应用上下文和异常报告集合 ConfigurableApplicationContext context = null; Collection exceptionReporters = new ArrayList(); // 设置系统属性 java.awt.headless,默认true configureHeadlessProperty(); // NO3 // 创建SpringApplicationRunListeners监听器,通过SpringFactoriesLoader加载,监听器在spring.factories中SpringApplicationRunListener接口,默认是只有org.springframework.boot.context.event.EventPublishingRunListener // 本质是一个事件发布者 SpringApplicationRunListeners listeners = getRunListeners(args); // 开始监听,表示springboot要开始启动了 // 广播ApplicationStartingEvent事件 listeners.starting(); try { // NO4 // 初始化默认应用参数类 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 加载springboot配置环境 // configurePropertySources(environment, args); 配置PropertySource // configureProfiles(environment, args); 配置profiles // 此时广播了一个ApplicationEnvironmentPreparedEvent事件,通知事件监听者,应用的environment已经准备完毕 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); // NO5 // Banner打印 Banner printedBanner = printBanner(environment); // NO6 创建应用上下文,根据webApplicationType应用类型的不同,创建不同的上下文,通过Class.forName的方式 // DEFAULT_CONTEXT_CLASS = "org.springframework.context.annotation.AnnotationConfigApplicationContext" // DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext" // DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext" context = createApplicationContext(); // 异常报告器,在spring.factories中SpringBootExceptionReporter接口 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); // NO7 // 准备应用上下文 // 给ApplicationContext设置environment // 遍历调用所有的ApplicationContextInitializer的 initialize()方法 // 广播ApplicationContextInitializedEvent事件,ApplicationContext初始化事件 // 将所有的bean加载到容器中 // 广播ApplicationPreparedEvent事件,ApplicationContext准备事件 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // NO8 // 刷新应用上下文,获取所有的BeanFactoryPostProcessor对容器进行一些额外操作 // 其中对于@Configuration、@ComponentScan、@Import、@PropertySource、@ImportResource、@Bean注解都是在这里处理的 // 这里的操作就是spring中的refresh方法那一套东西 refreshContext(context); // 应用上下文刷新后置处理(该方法为空方法) afterRefresh(context, applicationArguments); // 停止计时监控 stopWatch.stop(); if (this.logStartupInfo) { // 输出主类名以及时间信息 new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } // NO9 // 广播ApplicationStartedEvent事件,表示应用上下文已完成 listeners.started(context); // NO10 // 执行Runner运行器 ApplicationRunner和CommandLineRunner实现类 callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { // NO11 // 发布应用上下文就绪事件 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
NO7 准备应用上下文
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 设置环境 context.setEnvironment(environment); // 配置上下文的bean生成器以及资源加载器 postProcessApplicationContext(context); // 上下文初始化器执行initialize方法 applyInitializers(context); // 触发监听器的contextPrepared事件 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans // 注册两个特殊的单例bean ConfigurableListableBeanFactory 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 sources // 加载所有资源 Set sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); // 加载bean load(context, sources.toArray(new Object[0])); // 触发监听器的contextLoaded事件 listeners.contextLoaded(context); }
NO8 刷新应用上下文
这里实际调用的就是spring中的refresh方法 可参考 源码分析之上下文构建
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. // 设置beanFactory的一些属性 // 添加后置处理器 // 设置忽略的自动装配接口 // 注册一些组件 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
https://zhhll.icu/2021/框架/springboot/源码/2.启动原理/
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。