Java
程序的启动入口是在main
方法。因此如果我们要了解SpringBoot
的启动流程,那么我们可以从main
着手
入口 1 2 3 4 5 6 7 8 9 public class SpringbootApplication { public static void main (String[] args) { SpringApplication.run(SpringbootApplication.class, args); } } public static ConfigurableApplicationContext run (Object[] sources, String[] args) { return new SpringApplication (sources).run(args); }
构造SpringApplication 构造SpringApplication
对象。在其内部进行初始化操作
1 2 3 4 5 6 7 8 9 10 private void initialize (Object[] sources) { if (sources != null && sources.length > 0 ) { this .sources.addAll(Arrays.asList(sources)); } this .webEnvironment = deduceWebEnvironment(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this .mainApplicationClass = deduceMainApplicationClass(); }
判断是否是Web程序 首先将当前类添加到启动类中,判断是否是Web
程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private boolean deduceWebEnvironment () { for (String className : WEB_ENVIRONMENT_CLASSES) { if (!ClassUtils.isPresent(className, null )) { return false ; } } return true ; } public static boolean isPresent (String className, ClassLoader classLoader) { try { forName(className, classLoader); return true ; } catch (Throwable ex) { return false ; } }
通过判断javax.servlet.Servlet
,org.springframework.web.context.ConfigurableWebApplicationContext
能否被加载类确定是否是Web
程序
找出所有应用初始化器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 private <T> Collection<? extends T > getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Set<String> names = new LinkedHashSet <String>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; } private <T> List<T> createSpringFactoriesInstances (Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList <T>(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; }
从spring.factories
文件中找出key
为ApplicationContextInitializer
的类实例并实例化,默认情况下从spring.factories
文件中找出的key
为ApplicationContextInitializer
的类有以下五种:
org.springframework.boot.context.config.DelegatingApplicationContextInitializer
org.springframework.boot.context.ContextIdApplicationContextInitializer
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
找出所有应用程序监听器 从spring.factories
中找出所有key
为ApplicationListener
的应用程序监听器,过程跟找出应用程序初始化器一致。
默认情况下,被加载的应用程序监听器有
org.springframework.boot.context.config.ConfigFileApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
org.springframework.boot.logging.LoggingApplicationListener
org.springframework.boot.logging.ClasspathLoggingApplicationListener
org.springframework.boot.autoconfigure.BackgroundPreinitializer
org.springframework.boot.context.config.DelegatingApplicationListener
org.springframework.boot.builder.ParentContextCloserApplicationListener
org.springframework.boot.ClearCachesApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
这些监听器在应用程序启动之后会回调执行对应的逻辑操作
SpringApplication run 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public ConfigurableApplicationContext run (String... args) { StopWatch stopWatch = new StopWatch (); stopWatch.start(); ConfigurableApplicationContext context = null ; FailureAnalyzers analyzers = null ; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments ( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); Banner printedBanner = printBanner(environment); context = createApplicationContext(); analyzers = new FailureAnalyzers (context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); listeners.finished(context, null ); stopWatch.stop(); if (this .logStartupInfo) { new StartupInfoLogger (this .mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException (ex); } }
首先构造StopWatch
来统计每个任务的运行时间。
1 2 3 4 5 private SpringApplicationRunListeners getRunListeners (String[] args) { Class<?>[] types = new Class <?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners (logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this , args)); }
获取所有的应用程序监听器,然后开始监听。构建DefaultApplicationArguments
1 2 3 4 5 6 7 8 9 10 11 12 13 private ConfigurableEnvironment prepareEnvironment ( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); listeners.environmentPrepared(environment); if (!this .webEnvironment) { environment = new EnvironmentConverter (getClassLoader()) .convertToStandardEnvironmentIfNecessary(environment); } return environment; }
准备运行环境,获取或创建环境。配置属性,这个时候resources
里的属性被读取。配置运行环境(profile)。回调监听器告知环境已经配置完成
1 2 3 4 5 6 7 8 9 10 11 12 13 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); }
打印Banner
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 protected ConfigurableApplicationContext createApplicationContext () { Class<?> contextClass = this .applicationContextClass; if (contextClass == null ) { try { contextClass = Class.forName(this .webEnvironment ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS); } catch (ClassNotFoundException ex) { throw new IllegalStateException ( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass" , ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass); }
创建应用程序上下文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 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); } context.getBeanFactory().registerSingleton("springApplicationArguments" , applicationArguments); if (printedBanner != null ) { context.getBeanFactory().registerSingleton("springBootBanner" , printedBanner); } Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty" ); load(context, sources.toArray(new Object [sources.size()])); listeners.contextLoaded(context); }
准备上下文
1 2 3 4 5 6 7 8 9 10 11 private void refreshContext (ConfigurableApplicationContext context) { refresh(context); if (this .registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { } } }
刷新上下文
所有的这些过程都会通过SpringApplicationRunListener
对外发送SpringApplicationEvent
事件,这是一个订阅发布模式
总结 SpringBoot
启动时,会加载各种初始化器,监听器,然后会通过订阅发布模式对所有的监听者发送启动过程