玩转springboot之springboot启动原理

avatar
作者
猴君
阅读量:1

启动原理

注意:使用版本为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<SpringBootExceptionReporter> 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<Object> 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.启动原理/

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!