SpringBoot超详细分析启动流程

Springboot启动类

@SpringBootApplication
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

SpringBootApplication注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

@SpringBootApplication注解上标注了@EnableAutoConfiguration,表示TestApplication是引导类。

Springboot的启动方法中传入了两个参数,引导类,和程序参数。

public static ConfigurableApplicationContext run(Class primarySource, String... args) {
   return run(new Class[] { primarySource }, args);
}

调用run方法

public static ConfigurableApplicationContext run(Class[] primarySources, String[] args) {
   return new SpringApplication(primarySources).run(args);
}

run方法中有两步,创建SpringApplication和执行SpringApplication的run方法。

1、创建SpringApplication

SpringApplication的构造器

public SpringApplication(Class... primarySources) {
   this(null, primarySources);
}
private ResourceLoader resourceLoader;
private Set> primarySources;
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
   //将resourceLoader赋值成员变量,此处是null
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
    //将引导类赋值成员变量
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //判断web类型,赋值成员变量
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   //加载初始化器
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //加载监听器
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //获得引导类
   this.mainApplicationClass = deduceMainApplicationClass();
}

1.1、判断web类型

//org.springframework.boot.WebApplicationType#deduceFromClasspath
static WebApplicationType deduceFromClasspath() {
    //WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
//JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
   if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
         && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
      return WebApplicationType.REACTIVE;
   }
    //SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" }
   for (String className : SERVLET_INDICATOR_CLASSES) {
      if (!ClassUtils.isPresent(className, null)) {
         return WebApplicationType.NONE;
      }
   }
   return WebApplicationType.SERVLET;
}

1.2、加载上下文初始化器

利用spi加载 ApplicationContextInitializer 的实现类

private  Collection getSpringFactoriesInstances(Class type) {
   return getSpringFactoriesInstances(type, new Class[] {});
}
private  Collection getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args) {
    //获取classloader
   ClassLoader classLoader = getClassLoader();
   // Use names and ensure unique to protect against duplicates
    //获取配置文件中接口实现类的全限定名
   Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //初始化
   List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
   AnnotationAwareOrderComparator.sort(instances);
    //返回
   return instances;
}
public ClassLoader getClassLoader() {
   if (this.resourceLoader != null) {
      return this.resourceLoader.getClassLoader();
   }
   return ClassUtils.getDefaultClassLoader();
}
private  List createSpringFactoriesInstances(Class type, Class[] parameterTypes,
      ClassLoader classLoader, Object[] args, Set names) {
   List instances = new ArrayList<>(names.size());
   for (String name : names) {
      try {
         Class instanceClass = ClassUtils.forName(name, classLoader);
         Assert.isAssignable(type, instanceClass);
         Constructor constructor = instanceClass.getDeclaredConstructor(parameterTypes);
         T instance = (T) BeanUtils.instantiateClass(constructor, args);
         instances.add(instance);
      }
      catch (Throwable ex) {
         throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
      }
   }
   return instances;
}

将初始化好的上下文初始化器设置到成员变量

//private List> initializers;
public void setInitializers(Collection> initializers) {
   this.initializers = new ArrayList<>(initializers);
}

1.3、加载监听器

将初始化好的监听器设置到成员变量

//private List> listeners;
public void setListeners(Collection> listeners) {
   this.listeners = new ArrayList<>(listeners);
}

1.4、获得引导类类型

private Class deduceMainApplicationClass() {
   try {
      StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
      for (StackTraceElement stackTraceElement : stackTrace) {
         //获取main方法的类
         if ("main".equals(stackTraceElement.getMethodName())) {
            return Class.forName(stackTraceElement.getClassName());
         }
      }
   }
   catch (ClassNotFoundException ex) {
      // Swallow and continue
   }
   return null;
}

2、执行SpringApplication的run方法启动Springboot

public ConfigurableApplicationContext run(String... args) {
    //启动停止监听器
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
    //Spring上下文
   ConfigurableApplicationContext context = null;
    //错误导出
   Collection exceptionReporters = new ArrayList<>();
   configureHeadlessProperty();
    //运行时监听器
   SpringApplicationRunListeners listeners = getRunListeners(args);
    //启动运行时监听器
   listeners.starting();
   try {
       //生成ApplicationArguments
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
       //准备environment
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      configureIgnoreBeanInfo(environment);
       //打印banner
      Banner printedBanner = printBanner(environment);
       //创建Spring上下文
      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;
}

2.1、准备environment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments) {
   // Create and configure the environment
    //创建environment
   ConfigurableEnvironment environment = getOrCreateEnvironment();
    //配置environment
   configureEnvironment(environment, applicationArguments.getSourceArgs());
   ConfigurationPropertySources.attach(environment);
   listeners.environmentPrepared(environment);
   bindToSpringApplication(environment);
   if (!this.isCustomEnvironment) {
      environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
            deduceEnvironmentClass());
   }
   ConfigurationPropertySources.attach(environment);
   return environment;
}

2.1.1、创建environment

private ConfigurableEnvironment getOrCreateEnvironment() {
   if (this.environment != null) {
      return this.environment;
   }
   switch (this.webApplicationType) {
   case SERVLET:
      return new StandardServletEnvironment();
   case REACTIVE:
      return new StandardReactiveWebEnvironment();
   default:
      return new StandardEnvironment();
   }
}

这里根据web类型创建不同的environment

2.1.2、配置environment

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
   if (this.addConversionService) {
       //转换服务
      ConversionService conversionService = ApplicationConversionService.getSharedInstance();
      environment.setConversionService((ConfigurableConversionService) conversionService);
   }
   configurePropertySources(environment, args);
   configureProfiles(environment, args);
}

配置PropertySources

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
   MutablePropertySources sources = environment.getPropertySources();
   if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
      sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
   }
   if (this.addCommandLineProperties && args.length > 0) {
      String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
      if (sources.contains(name)) {
         PropertySource source = sources.get(name);
         CompositePropertySource composite = new CompositePropertySource(name);
         composite.addPropertySource(
               new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
         composite.addPropertySource(source);
         sources.replace(name, composite);
      }
      else {
         sources.addFirst(new SimpleCommandLinePropertySource(args));
      }
   }
}

主要为了在PropertySources添加一个SimpleCommandLinePropertySource。

配置profiles

protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
   Set profiles = new LinkedHashSet<>(this.additionalProfiles);
   profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
   environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}

将profile添加到environment

2.2、打印Banner

private Banner.Mode bannerMode = Banner.Mode.CONSOLE;
private Banner printBanner(ConfigurableEnvironment environment) {
   //无需打印
   if (this.bannerMode == Banner.Mode.OFF) {
      return null;
   }
   ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
         : new DefaultResourceLoader(getClassLoader());
   SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
   if (this.bannerMode == Mode.LOG) {
      return bannerPrinter.print(environment, this.mainApplicationClass, logger);
   }
   return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

2.3、创建Spring上下文

//DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."			//+"web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
//DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."	//+"boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
//DEFAULT_CONTEXT_CLASS = "org.springframework.context."
//			+ "annotation.AnnotationConfigApplicationContext";
protected ConfigurableApplicationContext createApplicationContext() {
   Class contextClass = this.applicationContextClass;
   if (contextClass == null) {
      try {
         switch (this.webApplicationType) {
         case SERVLET:
            contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
            break;
         case REACTIVE:
            contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
            break;
         default:
            contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
         }
      }
      catch (ClassNotFoundException ex) {
         throw new IllegalStateException(
               "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
      }
   }
    //初始化上下文并返回
   return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

2.4、准备上下文

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
      SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
   context.setEnvironment(environment);
    //ApplicationContext的后置处理
   postProcessApplicationContext(context);
    //应用初始化器
   applyInitializers(context);
    //运行时监听器的准备上下文监听
   listeners.contextPrepared(context);
   if (this.logStartupInfo) {
      logStartupInfo(context.getParent() == null);
      logStartupProfileInfo(context);
   }
   // Add boot specific singleton beans
    //获取beanFactory
   ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    //将程序入参注册bean springApplicationArguments
   beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    //将banner注册bean springBootBanner
   if (printedBanner != null) {
      beanFactory.registerSingleton("springBootBanner", printedBanner);
   }
    //设置BeanDefinition是否允许重写
   if (beanFactory instanceof DefaultListableBeanFactory) {
      ((DefaultListableBeanFactory) beanFactory)
            .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
    //初始化允许懒加载,设置BeanfactorypostProcessor
   if (this.lazyInitialization) {
      context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
   }
   // Load the sources
    //获取source
   Set sources = getAllSources();
   Assert.notEmpty(sources, "Sources must not be empty");
   load(context, sources.toArray(new Object[0]));
    //运行时监听器,上下文加载完成
   listeners.contextLoaded(context);
}
 
  
 

2.4.1、ApplicationContext的后置处理

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
    //注册 beanNameGenerator
   if (this.beanNameGenerator != null) {
      context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
            this.beanNameGenerator);
   }
    //注册 resourceLoader
   if (this.resourceLoader != null) {
      if (context instanceof GenericApplicationContext) {
         ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
      }
      if (context instanceof DefaultResourceLoader) {
         ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
      }
   }
    //设置 ConversionService
   if (this.addConversionService) {
      context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
   }
}
//org.springframework.boot.convert.ApplicationConversionService#getSharedInstance
public static ConversionService getSharedInstance() {
   ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance;
   if (sharedInstance == null) {
      synchronized (ApplicationConversionService.class) {
         sharedInstance = ApplicationConversionService.sharedInstance;
         if (sharedInstance == null) {
            sharedInstance = new ApplicationConversionService();
            ApplicationConversionService.sharedInstance = sharedInstance;
         }
      }
   }
   return sharedInstance;
}

2.4.2、应用初始化器

protected void applyInitializers(ConfigurableApplicationContext context) {
   for (ApplicationContextInitializer initializer : getInitializers()) {
      Class requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
            ApplicationContextInitializer.class);
      Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
      initializer.initialize(context);
   }
}

执行所有实现了 ApplicationContextInitializer 接口的类的initialize方法。

2.4.3、获取sources

public Set getAllSources() {
   Set allSources = new LinkedHashSet<>();
   if (!CollectionUtils.isEmpty(this.primarySources)) {
      allSources.addAll(this.primarySources);
   }
   if (!CollectionUtils.isEmpty(this.sources)) {
      allSources.addAll(this.sources);
   }
   return Collections.unmodifiableSet(allSources);
}
 
  
 

这里组装了引导类和自定义的source

2.4.4、加载

protected void load(ApplicationContext context, Object[] sources) {
   if (logger.isDebugEnabled()) {
      logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
   }
    //创建BeanDefinitionLoader
   BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
   if (this.beanNameGenerator != null) {
      loader.setBeanNameGenerator(this.beanNameGenerator);
   }
   if (this.resourceLoader != null) {
      loader.setResourceLoader(this.resourceLoader);
   }
   if (this.environment != null) {
      loader.setEnvironment(this.environment);
   }
    //加载,spring的逻辑,这里会将引导类注册
   loader.load();
}
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
   return new BeanDefinitionLoader(registry, sources);
}

2.5、刷新上下文

private void refreshContext(ConfigurableApplicationContext context) {
   refresh(context);
   if (this.registerShutdownHook) {
      try {
          //注册钩子	关闭SpringBoot容器
         context.registerShutdownHook();
      }
      catch (AccessControlException ex) {
         // Not allowed in some environments.
      }
   }
}

刷新

protected void refresh(ApplicationContext applicationContext) {
   Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    //执行spring容器的刷新
   ((AbstractApplicationContext) applicationContext).refresh();
}

2.6、上下文刷新后

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}

这里是一个空实现,应该是作为模板扩展吧。

2.7、执行回调

private void callRunners(ApplicationContext context, ApplicationArguments args) {
   List runners = new ArrayList<>();
   runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
   runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
   AnnotationAwareOrderComparator.sort(runners);
   for (Object runner : new LinkedHashSet<>(runners)) {
      if (runner instanceof ApplicationRunner) {
         callRunner((ApplicationRunner) runner, args);
      }
      if (runner instanceof CommandLineRunner) {
         callRunner((CommandLineRunner) runner, args);
      }
   }
}
 
  
 

这里会调用所有实现了ApplicationRunner,CommandLineRunner的接口的实现类的run方法。

到此这篇关于SpringBoot超详细分析启动流程的文章就介绍到这了,更多相关SpringBoot启动分析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(SpringBoot超详细分析启动流程)