SpringBoot启动流程

SpringBoot核心启动类的SpringApplication。从SpringApplication.run()开始先创建SpringApplication对象,并调用该对象的run方法。

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

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
    return new SpringApplication(sources).run(args);//在这个静态方法中,创建SpringApplication对象,并调用该对象的run方法。
}

构建SpringApplication对象

初始化SpringApplication的source

public SpringApplication(Object... sources) {
    initialize(sources);
}

//初始化SpringApplication对象的成员变量sources,webEnvironment,initializers,listeners,mainApplicationClass。
//sources的赋值比较简单,就是我们传给SpringApplication.run方法的参数。
private void initialize(Object[] sources) {
    // 为成员变量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();
}

初始化SpringApplication的webEnvironment

private boolean webEnvironment; 

private static final String[] WEB_ENVIRONMENT_CLASSES = {   "javax.servlet.Servlet",    "org.springframework.web.context.ConfigurableWebApplicationContext" };
//可以看到webEnvironment是一个boolean,该成员变量用来表示当前应用程序是不是一个Web应用程序。//那么怎么决定当前应用程序是否Web应用程序呢,是通过在classpath中查看是否存在WEB_ENVIRONMENT_CLASSES这个数组中所包含的类,//如果存在那么当前程序即是一个Web应用程序,反之则不然。
private boolean deduceWebEnvironment() {
    for (String className : WEB_ENVIRONMENT_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return false;
        }
    }
    return true;
}

初始化SpringApplication的initializers

//initializers成员变量,是一个ApplicationContextInitializer类型对象的集合
private List<ApplicationContextInitializer<?>> initializers;
public void setInitializers(
        Collection<? extends ApplicationContextInitializer<?>> initializers) {
    this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
    this.initializers.addAll(initializers);
}

private void initialize(Object[] sources) {
    ...
    // 为成员变量initializers赋值
    //关键是调用getSpringFactoriesInstances(ApplicationContextInitializer.class),来获取ApplicationContextInitializer类型对象的列表。
    setInitializers((Collection) getSpringFactoriesInstances(
            ApplicationContextInitializer.class));
    ...
}
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}
//首先通过调用SpringFactoriesLoader.loadFactoryNames(type, classLoader)来获取所有Spring Factories的名字,//然后调用createSpringFactoriesInstances方法根据读取到的名字创建对象。//最后会将创建好的对象列表排序并返回。
//可以看到,是从一个名字叫spring.factories的资源文件中,读取key为org.springframework.context.ApplicationContextInitializer的value。
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
        Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    // Use names and ensure unique to protect against duplicates
    Set<String> names = new LinkedHashSet<String>(
            SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
            classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    try {
        Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        List<String> result = new ArrayList<String>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
            String factoryClassNames = properties.getProperty(factoryClassName);
            result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
        }
        return result;
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}
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.getConstructor(parameterTypes);
            T instance = (T) constructor.newInstance(args);
            instances.add(instance);
        }
        catch (Throwable ex) {
            throw new IllegalArgumentException(
                    "Cannot instantiate " + type + " : " + name, ex);
        }
    }
    return instances;
}

spring.factories的部分内容如下:
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,org.springframework.boot.context.ContextIdApplicationContextInitializer,org.springframework.boot.context.config.DelegatingApplicationContextInitializer,org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer

初始化SpringApplication的listeners

//listeners成员变量,是一个ApplicationListener<?>类型对象的集合
private List<ApplicationListener<?>> listeners;
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
    this.listeners = new ArrayList<ApplicationListener<?>>();
    this.listeners.addAll(listeners);
}

private void initialize(Object[] sources) {
    ...
    // 为成员变量listeners赋值
    //可以看到获取该成员变量内容使用的是跟成员变量initializers一样的方法,  //只不过传入的类型从ApplicationContextInitializer.class变成了ApplicationListener.class。
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    ...
}
spring.factories中的相关内容:
# Application Listeners
org.springframework.context.ApplicationListener=org.springframework.boot.builder.ParentContextCloserApplicationListener,org.springframework.boot.context.FileEncodingApplicationListener,org.springframework.boot.context.config.AnsiOutputApplicationListener,org.springframework.boot.context.config.ConfigFileApplicationListener,org.springframework.boot.context.config.DelegatingApplicationListener,org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,org.springframework.boot.logging.ClasspathLoggingApplicationListener,org.springframework.boot.logging.LoggingApplicationListener

初始化SpringApplication的mainApplicationClass

private Class<?> mainApplicationClass;
private void initialize(Object[] sources) {
    ...
    // 为成员变量mainApplicationClass赋值
    this.mainApplicationClass = deduceMainApplicationClass();
    ...
}
//通过获取当前调用栈,找到入口方法main所在的类,并将其复制给SpringApplication对象的成员变量mainApplicationClass。
private Class<?> deduceMainApplicationClass() {
    try {
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}

启动SpringApplication

经过上面的初始化过程,我们已经有了一个SpringApplication对象,根据SpringApplication类的静态run方法一节中的分析,接下来会调用SpringApplication对象的run方法。我们接下来就分析这个对象的run方法。

//可变个数参数args即是我们整个应用程序的入口main方法的参数
//StopWatch是来自org.springframework.util的工具类,可以用来方便的记录程序的运行时间。
//SpringApplication对象的run方法创建并刷新ApplicationContext
public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    configureHeadlessProperty();
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.started();
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);
        context = createAndRefreshContext(listeners, applicationArguments);
        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, ex);
        throw new IllegalStateException(ex);
    }
}

headless模式

//实际上是就是设置系统属性java.awt.headless,一般运行在没有显示器和键盘的环境时设置为true
private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
private boolean headless = true;

public ConfigurableApplicationContext run(String... args) {
    ...
    //设置headless模式
        configureHeadlessProperty();
    ...
}
private void configureHeadlessProperty() {
    System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
            SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}

获取listeners

//run方法中,加载了一系列SpringApplicationRunListener对象,//在创建和更新ApplicationContext方法前后分别调用了listeners对象的started方法和finished方法, //并在创建和刷新ApplicationContext时,将listeners作为参数传递到了createAndRefreshContext方法中,//以便在创建和刷新ApplicationContext的不同阶段,调用listeners的相应方法以执行操作。//所以,所谓的SpringApplicationRunListeners实际上就是在SpringApplication对象的run方法执行的不同阶段,去执行一些操作,并且这些操作是可配置的。
public ConfigurableApplicationContext run(String... args) {
    ...
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.started();
    /**
         * 创建并刷新ApplicationContext
         * context = createAndRefreshContext(listeners, applicationArguments);
        **/
    listeners.finished(context, null);
    ...
}
//同时,可以看到,加载SpringApplicationRunListener时,使用的是跟加载ApplicationContextInitializer和ApplicationListener时一样的方法。//那么加载了什么,就可以从spring.factories文件中看到了:
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
            SpringApplicationRunListener.class, types, this, args));
}
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=org.springframework.boot.context.event.EventPublishingRunListener

创建并刷新ApplicationContext

//首先是创建一个DefaultApplicationArguments对象,
//之后调用createAndRefreshContext方法创建并刷新一个ApplicationContext,
//最后调用afterRefresh方法在刷新之后做一些操作。
public ConfigurableApplicationContext run(String... args) {
    ...
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);
        context = createAndRefreshContext(listeners, applicationArguments);
        afterRefresh(context, applicationArguments);
        ...
    }
    catch (Throwable ex) {
        handleRunFailure(context, listeners, ex);
        throw new IllegalStateException(ex);
    }
}
//创建一个DefaultApplicationArguments对象
DefaultApplicationArguments(String[] args) {
    Assert.notNull(args, "Args must not be null");
    this.source = new Source(args);
    this.args = args;
}
private static class Source extends SimpleCommandLinePropertySource {
    Source(String[] args) {
        super(args);
    }
    ...
}
public SimpleCommandLinePropertySource(String... args) {
    super(new SimpleCommandLineArgsParser().parse(args));
}
//createAndRefreshContext方法创建并刷新一个ApplicationContext
private ConfigurableEnvironment environment;
private boolean webEnvironment;
private ConfigurableApplicationContext createAndRefreshContext(
        SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    ConfigurableApplicationContext context;
    // 创建并配置Environment
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    listeners.environmentPrepared(environment);//发送事件
    if (isWebEnvironment(environment) && !this.webEnvironment) {
        environment = convertToStandardEnvironment(environment);
    }
    ...
    return context;
}
//Spring Application的Environment代表着程序运行的环境,
//主要包含了两种信息,一种是profiles,用来描述哪些bean definitions是可用的;
//一种是properties,用来描述系统的配置,其来源可能是配置文件、JVM属性文件、操作系统环境变量等等
private ConfigurableEnvironment getOrCreateEnvironment() {
  //首先要调用getOrCreateEnvironment方法获取一个Environment对象
  //执行到此处时,environment成员变量为null,而webEnvironment成员变量的值为true,所以会创建一个StandardServletEnvironment对象并返回
if (this.environment != null) {
       return this.environment;
   }
  if (this.webEnvironment) {
return new StandardServletEnvironment();
    }
return new StandardEnvironment();
}
private Map<String, Object> defaultProperties;
private boolean addCommandLineProperties = true;
private Set<String> additionalProfiles = new HashSet<String>();
//调用configureEnvironment方法来配置上一步获取的Environment对象.
protected void configureEnvironment(ConfigurableEnvironment environment,
        String[] args) {
  //configureEnvironment方法先是调用configurePropertySources来配置properties,然后调用configureProfiles来配置profiles
    configurePropertySources(environment, args);
    configureProfiles(environment, args);
}
protected void configurePropertySources(ConfigurableEnvironment environment,
        String[] args) {
    MutablePropertySources sources = environment.getPropertySources();
  //configurePropertySources首先查看SpringApplication对象的成员变量defaultProperties
    if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
    //如果该变量非null且内容非空,则将其加入到Environment的PropertySource列表的最后。
        sources.addLast(
                new MapPropertySource("defaultProperties", this.defaultProperties));
    }
  //然后查看SpringApplication对象的成员变量addCommandLineProperties和main函数的参数args
    if (this.addCommandLineProperties && args.length > 0) {
    //如果设置了addCommandLineProperties=true,且args个数大于0
       //那么就构造一个由main函数的参数组成的PropertySource放到Environment的PropertySource列表的最前面
    //(这就能保证,我们通过main函数的参数来做的配置是最优先的,可以覆盖其他配置)
    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(
                    name + "-" + args.hashCode(), args));
            composite.addPropertySource(source);
            sources.replace(name, composite);
        }
        else {
            sources.addFirst(new SimpleCommandLinePropertySource(args));
        }
    }
}
//configureProfiles首先会读取Properties中key为spring.profiles.active的配置项,配置到Environment
//然后再将SpringApplication对象的成员变量additionalProfiles加入到Environment的active profiles配置中
//配置文件里没有spring.profiles.active的配置项
//而SpringApplication对象的成员变量additionalProfiles也是一个空的集合,所以这个函数没有配置任何active profile
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
    environment.getActiveProfiles(); // ensure they are initialized
    // But these ones should go first (last wins in a property key clash)
    Set<String> profiles = new LinkedHashSet<String>(this.additionalProfiles);
    profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
    environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
}
//Environment就算是配置完成了.
//接下来调用SpringApplicationRunListeners类的对象listeners发布ApplicationEnvironmentPreparedEvent事件.然后listener进行各种响应。//省略各个listener响应逻辑

//打印banner,printBanner方法中,
//首先会调用selectBanner方法得到一个banner对象,
//然后判断bannerMode的类型,如果是Banner.Mode.LOG,那么将banner对象转换为字符串,打印一条info日志,
//否则的话,调用banner对象的printbanner方法,将banner打印到标准输出System.out。
private Banner banner;
private Banner.Mode bannerMode = Banner.Mode.CONSOLE;
public static final String BANNER_LOCATION_PROPERTY = "banner.location";
public static final String BANNER_LOCATION_PROPERTY_VALUE = "banner.txt";
private static final Banner DEFAULT_BANNER = new SpringBootBanner();
private ConfigurableApplicationContext createAndRefreshContext(
        SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    ...
    if (this.bannerMode != Banner.Mode.OFF) {
        printBanner(environment);
    }
    ...
}
protected void printBanner(Environment environment) {
    Banner selectedBanner = selectBanner(environment);
    if (this.bannerMode == Banner.Mode.LOG) {
        try {
            logger.info(createStringFromBanner(selectedBanner, environment));
        }
        catch (UnsupportedEncodingException ex) {
            logger.warn("Failed to create String for banner", ex);
        }
    }
    else {
        selectedBanner.printBanner(environment, this.mainApplicationClass,
                System.out);
    }
}
private Banner selectBanner(Environment environment) {
    String location = environment.getProperty(BANNER_LOCATION_PROPERTY,
            BANNER_LOCATION_PROPERTY_VALUE);
    ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
            : new DefaultResourceLoader(getClassLoader());
    Resource resource = resourceLoader.getResource(location);
    if (resource.exists()) {
        return new ResourceBanner(resource);
    }
    if (this.banner != null) {
        return this.banner;
    }
    return DEFAULT_BANNER;
}

private String createStringFromBanner(Banner banner, Environment environment)
        throws UnsupportedEncodingException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    banner.printBanner(environment, this.mainApplicationClass, new PrintStream(baos));
    String charset = environment.getProperty("banner.charset", "UTF-8");
    return baos.toString(charset);
}

//bannerMode是Banner.Mode.Console,而且也不曾提供过banner.txt这样的资源文件。
//所以selectBanner方法中得到到便是默认的banner对象,即SpringBootBanner类的对象:
//先打印个Spring的图形,然后打印个Spring Boot的文本,再然后打印一下Spring Boot的版本。
private static final String[] BANNER = { "",
        "  .   ____          _            __ _ _",
        " /\\\\ / ___‘_ __ _ _(_)_ __  __ _ \\ \\ \\ \\",
        "( ( )\\___ | ‘_ | ‘_| | ‘_ \\/ _` | \\ \\ \\ \\",
        " \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )",
        "  ‘  |____| .__|_| |_|_| |_\\__, | / / / /",
        " =========|_|==============|___/=/_/_/_/" };

private static final String SPRING_BOOT = " :: Spring Boot :: ";
private static final int STRAP_LINE_SIZE = 42;
@Override
public void printBanner(Environment environment, Class<?> sourceClass,
        PrintStream printStream) {
    for (String line : BANNER) {
        printStream.println(line);
    }
    String version = SpringBootVersion.getVersion();
    version = (version == null ? "" : " (v" + version + ")");
    String padding = "";
    while (padding.length() < STRAP_LINE_SIZE
            - (version.length() + SPRING_BOOT.length())) {
        padding += " ";
    }
    printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT,
            AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version));
    printStream.println();
}
//创建ApplicationContext
private Class<? extends ConfigurableApplicationContext> applicationContextClass;
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
        + "annotation.AnnotationConfigApplicationContext";
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
        + "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";

private ConfigurableApplicationContext createAndRefreshContext(
        SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    ConfigurableApplicationContext context;
    ...
    //创建ApplicationContext对象
    context = createApplicationContext();
    //将我们之前准备好的Environment对象赋值进去
    context.setEnvironment(environment);
    //调用postProcessApplicationContext和applyInitializers做一些处理和初始化的操作
    postProcessApplicationContext(context);
    applyInitializers(context);
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    ...
    return context;
}

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方法来创建ApplicationContext对象
BeanUtils.instantiate(contextClass);
}
//通过调用Class对象的newInstance()方法来实例化对象,这等同于直接调用类的空的构造方法
public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {
    Assert.notNull(clazz, "Class must not be null");
    if (clazz.isInterface()) {
        throw new BeanInstantiationException(clazz, "Specified class is an interface");
    }
    try {
        return clazz.newInstance();
    }
    catch (InstantiationException ex) {
        throw new BeanInstantiationException(clazz, "Is it an abstract class?", ex);
    }
    catch (IllegalAccessException ex) {
        throw new BeanInstantiationException(clazz, "Is the constructor accessible?", ex);
    }
}
//构造方法中初始化了两个成员变量,
//类型分别为AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
//用以加载使用注解的bean定义。
public AnnotationConfigEmbeddedWebApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

@Override
public void setEnvironment(ConfigurableEnvironment environment) {
    super.setEnvironment(environment);
    this.reader.setEnvironment(environment);
    this.scanner.setEnvironment(environment);
}
//如果成员变量beanNameGenerator不为Null,那么为ApplicationContext对象注册beanNameGenerator bean。
//如果成员变量resourceLoader不为null,则为ApplicationContext对象设置ResourceLoader。
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
    if (this.webEnvironment) {
        if (context instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext configurableContext = (ConfigurableWebApplicationContext) context;
            if (this.beanNameGenerator != null) {
                configurableContext.getBeanFactory().registerSingleton(
                        AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                        this.beanNameGenerator);
            }
        }
    }
    if (this.resourceLoader != null) {
        if (context instanceof GenericApplicationContext) {
            ((GenericApplicationContext) context)
                    .setResourceLoader(this.resourceLoader);
        }
        if (context instanceof DefaultResourceLoader) {
            ((DefaultResourceLoader) context)
                    .setClassLoader(this.resourceLoader.getClassLoader());
        }
    }
}
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);
    }
}

public Set<ApplicationContextInitializer<?>> getInitializers() {
    return asUnmodifiableOrderedSet(this.initializers);
}

private static <E> Set<E> asUnmodifiableOrderedSet(Collection<E> elements) {
    List<E> list = new ArrayList<E>();
    list.addAll(elements);
    Collections.sort(list, AnnotationAwareOrderComparator.INSTANCE);
    return new LinkedHashSet<E>(list);
}
时间: 10-19

SpringBoot启动流程的相关文章

SpringBoot 启动流程

SpringBoot 启动流程 加载 resources/META-INF/spring.factories 中配置的 ApplicationContextInitializer 和 ApplicationListener. /** * 加载在框架内部使用的各种通用工厂 bean. * spring.factories 文件必须满足 Properties 文件格式,属性的 key 是接口或抽象类的全限定类名, * value 是一组由逗号分隔的实现类全类名. */ public final cl

SpringBoot启动流程分析(四):IoC容器的初始化过程

SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一):SpringApplication类初始化过程 SpringBoot启动流程分析(二):SpringApplication的run方法 SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法 SpringBoot启动流程分析(四

SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一):SpringApplication类初始化过程 SpringBoot启动流程分析(二):SpringApplication的run方法 SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法 SpringBoot启动流程分析(四

springboot启动流程(一)构造SpringApplication实例对象

所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 启动入口 本文是springboot启动流程的第一篇,涉及的内容是SpringApplication这个对象的实例化过程.为什么从SpringApplication这个对象说起呢?我们先看一段很熟悉的代码片段 @SpringBootApplication public class SpringBootLearnApplication { public static void main(Str

springboot启动流程简析

Spring Boot可以轻松创建独立的,生产级的基于Spring的应用程序,而这只需要很少的一些Spring配置.本文将从SpringBoot的启动流程角度简要的分析SpringBoot启动过程中主要做了哪些事情. 说明: springboot 2.0.6.RELEASE SpringBoot启动简要流程图 附原始大图链接 启动流程概述 启动流程从角度来看,主要分两个步骤.第一个步骤是构造一个SpringApplication应用,第二个步骤是调用它的run方法,启动应用. 1 构造Sprin

springboot启动流程(九)ioc依赖注入

所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 正文 在前面的几篇文章中,我们多次提到这么一个转化过程: Bean配置 --> BeanDefinition --> Bean对象 Bean的配置可以是xml配置,也可以是java配置.BeanDefinition配置在内存中数据对象,也是Bean的元数据.在springboot启动过程当中,refresh上下文这个步骤将会解析xml配置以及java配置,从而把Bean的配置解析成为Bea

springboot启动流程(四)application配置文件加载过程

所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 触发监听器加载配置文件 在上一篇文章中,我们看到了Environment对象的创建方法.同时也稍微提及了一下ConfigFileApplicationListener这个监听器,这个监听器主要工作是为了加载application.properties/yml配置文件的. 回顾一下prepareEnvironment方法的代码 private ConfigurableEnvironment p

springboot启动流程(六)ioc容器refresh过程(上篇)

所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 正文 在前面的几篇文章中,我们看到Environment创建.application配置文件的加载.ApplicationContext实例对象的创建.以及主类加载成为BeanDefinition.做了这么多的准备,终于到了核心的部分,也就是ioc容器的刷新. 这里,我们不免要再次回顾一下SpringAplication的run方法 public ConfigurableApplicatio

1.springboot启动流程

SpringBoot版本:2.1.2.RELEASE 1.maven <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> </parent> <dependency> <g