SpringBoot源码解析系列(1)之SpringBoot的启动流程

Spring Boot的启动流程

MainApplication

@SpringBootApplication(scanBasePackages = "cn.hanna.boot")
@Slf4j
public class MainApplication {
​
    public static void main(String[] args) {
        // 程序的入口,完成容器的初始化操作获
        ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
    }
}
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    // 将主程序类作为主要数据源放入Class数组中
        return run(new Class[]{primarySource}, args);
    }
​
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    // 1.创建SpringApplication对象 2.调用对象的run方法,完成容器的初始化操作(run方法是核心)
        return (new SpringApplication(primarySources)).run(args);
    }

new SpringApplication(primarySources)创建SpringApplication实例,进行初始化工作

public SpringApplication(Class<?>... primarySources) {
    this((ResourceLoader)null, primarySources);
}
​
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.sources = new LinkedHashSet();
    this.bannerMode = Mode.CONSOLE;
    this.logStartupInfo = true;
    this.addCommandLineProperties = true;
    this.addConversionService = true;
    this.headless = true;
    this.registerShutdownHook = true;
    this.additionalProfiles = new HashSet();
    this.isCustomEnvironment = false;
    this.lazyInitialization = false;
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
    // 1、选择web应用的类型NONE、SERVLET、REACTIVE
    // NONE:表示当前的应用即不是一个web应用也不是一个reactive应用,是一个纯后台的应用,不启动内嵌的服务
    // SERVLET:当前应用是一个基于servlet API的标准的web应用,需启动内嵌servlet web服务
    // Reactive:reactive是spring5当中的新特性,表示是一个响应式的web应用,需启动内嵌的响应式web服务
    // 判断依据:跟据类加载器,加载的类来进行判断的
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
   // 2、获取spring工厂文件中的实例,实际上就是获取/META-INF/spring.factories中提供的ApplicationContextInitializer类型的实例对象,获取完成后将其赋值给SpringApplication对象的List<ApplicationContextInitializer<?>> initializers属性
  this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 3、它与2一样,就是获取全部配置文件中ApplicationListener类型的listener集合,将其实例化,作为自己的listeners属性保存
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    // 设置主程序类,就是我们自定义的带有main方法的类(MainApplication启动类)
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

1. WebApplicationType#deduceFromClasspath()

static WebApplicationType deduceFromClasspath() {
    // ClassUtils.isPresent()方法,判断指定类名的类是否存在,是否可以进行加载(如果我们导入了,相对应的jar包,就可以加载,如果没有导入就不能加载)
    // 如果能够加载DispatcherHandler类,但是无法加载DispatcherServlet和ServletContainer类,就证明是一个响应式web应用
    if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
        return REACTIVE;
    } else {
        // SERVLET_INDICATOR_CLASSES = = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};
        String[] var0 = SERVLET_INDICATOR_CLASSES;
        int var1 = var0.length;
    // 如果不是响应式web应用,并且也不能加载Servlet或ConfigurableWebApplicationContext类,则证明是一个非web应用
        for(int var2 = 0; var2 < var1; ++var2) {
            String className = var0[var2];
            if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
                return NONE;
            }
        }
    // 如果能加载到Servlet和ConfigurableWebApplicationContext类,则证明是一个普通的servlet web应用
        return SERVLET;
    }
}
public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
        try {
       // 可以看到在isPresent()方法中又调用了 forName()
       // forName()方法内部主要做的事情就是:获取默认的类加载器,尝试直接加载className对应的类,如果失败,尝试加载该类的内部类,依旧失败,抛出异常
       // 如果forName()方法中没有抛出异常,表明加载类成功,返回true
       // 如果forName()方法中抛出异常,表明我们没有导入该类相对应的jar包,不打算使用此类作为应用程序的开发,返回false
            forName(className, classLoader);
            return true;
        } catch (IllegalAccessError var3) {
            throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" + className + "]: " + var3.getMessage(), var3);
        } catch (Throwable var4) {
            return false;
        }
    }

总结(应用类型的判断规则):

  • 如果应用程序存在DispatcherHandler并且不存在DispatcherServlet和ServletContainer则为响应式web应用,需加载并启动内嵌的响应式web服务。

  • 如果应用程序不包含Servlet或ConfigurableWebApplicationContext则为普通应用程序。

  • 其他情况则为基于servlet的web应用,需加载并启动内嵌的servlet web服务。

2.SpringApplication#getSpringFactoriesInstances

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    // 记住此处传入的是ApplicationContextInitializer.class
    return this.getSpringFactoriesInstances(type, new Class[0]);
}
​
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    // 获取SpringApplication的类加载器
    ClassLoader classLoader = this.getClassLoader();
    // 加载spring.factories文件中的类的全类名集合(此处调用loadFactoryNames()中传入的type是ApplicationContextInitializer.class)
    Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 通过反射获取到集合中全类名对应的Class,并创建其实例对象,返回实例对象列表
    List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    // 跟据优先级进行排序,返回排序后的实例列表
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

2.1 SpringFactoriesLoader#loadFactoryNames

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    // 获取ApplicationContextInitializer类的全类名(org.springframework.context.ApplicationContextInitializer)
    String factoryTypeName = factoryType.getName();
    //loadSpringFactories()才正式去加载spring.factories文件,获取文件中的内容,
    // getOrDefault()获取类型为ApplicationContextInitializer.class的全类名集合
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
​
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    // 从缓存中获取,首次一定获取不到
    MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
    if (result != null) {
        return result;
    } else {
        try {
      // 获取META-INF/spring.factories文件所在的全部的URL(绝对路径)
      //比如:我们导入的org.springframework.boot:spring-boot:xxx版本号和org.springframework.boot:spring-boot-autoconfigure:xxx版本号的jar包中就存在spring.factories文件
      // 总结:实际上就是去获取当前项目中所有META-INF/spring.factories文件的绝对路径
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            LinkedMultiValueMap result = new LinkedMultiValueMap();
            // 遍历URL
            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                UrlResource resource = new UrlResource(url);
            // 加载文件资源到Properties中
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                Iterator var6 = properties.entrySet().iterator();
            // 循环properties
                while(var6.hasNext()) {
                    Entry<?, ?> entry = (Entry)var6.next();
                    String factoryTypeName = ((String)entry.getKey()).trim();
                    String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                    int var10 = var9.length;
​
                    for(int var11 = 0; var11 < var10; ++var11) {
                        String factoryImplementationName = var9[var11];
         // 将spring.factories中类型以及对应的实现类的全类名,放入Map<String,LinkedList<String>>中
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }
        // 将该类加载器加载的spring.factories文件中的结果集放入缓存,
            cache.put(classLoader, result);
            return result;
        } catch (IOException var13) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
        }
    }
}

org.springframework.boot:spring-boot:xxx版本

org.springframework.boot:spring-boot-autoconfigure:xxx版本

spring.factories文件

遍历完成后拿到的result

ApplicationContextInitializer类型的全类名集合

ApplicationContextInitializer类型的类实例化对象列表

总结:this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class))

内部的方法:就是去加载当前项目下全部的spring.factories文件,将文件中的key-value放入缓存中,并将读取到的ApplicationContextInitializer类型的类实例化

外部方法:将实例化好的实例对象集合设置为SpringApplication的initializers属性值

看一下,获取到的listeners集合

SpringApplication#run核心方法,完成容器的初始化工作

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    // 保存程序的启动时间
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
    this.configureHeadlessProperty();
    //1. 获取运行监听器(重要)
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    // 2.启动获取到的每一个SpringApplicationRunListener类型的监听器(目前我们之获取到了一个EventPublishingRunListener)
    listeners.starting();
​
    Collection exceptionReporters;
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
     // 3.准备环境(在准备环境的过程中就会加载类路径下的:配置文件中的信息)
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
        // 配置忽略bean信息
        this.configureIgnoreBeanInfo(environment);
        // 在控制台打印Spring标志
        Banner printedBanner = this.printBanner(environment);
        // 4.创建应用上下文
        context = this.createApplicationContext();
        // 获取记录异常的对象
        exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
        // 5.准备上下文环境
        this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 6.刷新上下文
        this.refreshContext(context);
        // 7.空方法
        this.afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
        }
        /**
        1.创建应用上下文启动完成事件对象ApplicationStartedEvent
        2.发布应用上下文启动完成事件,广播事件,调用监听器相对应的监听方法
        **/
        listeners.started(context);
        this.callRunners(context, applicationArguments);
    } catch (Throwable var10) {
        this.handleRunFailure(context, var10, exceptionReporters, listeners);
        throw new IllegalStateException(var10);
    }
​
    try {
        // 发布应用准备就绪的事件
        listeners.running(context);
        return context;
    } catch (Throwable var9) {
        this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
        throw new IllegalStateException(var9);
    }
}

1.SpringApplication#getRunListeners

private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
    //1.getSpringFactoriesInstances()方法我们前面分析过:
    // ①去获取spring.factories文件中的指定类型(SpringApplicationRunListener接口)的类的全类名的集合,
    // ②在spring.factories中,一般会发现一个EventPublishingRunListener类型的运行监听器
    // ③通过反射,实例化EventPublishingRunListener对象
    // 2.创建SpringApplicationRunListeners对象,设置它的listeners属性为获取到的运行监听器集合
    /**
SpringApplicationRunListeners(Log log, Collection<? extends         SpringApplicationRunListener> listeners) {
        this.log = log;
        this.listeners = new ArrayList(listeners);
    }
    **/
    return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

1.1 EventPublishingRunListener

public EventPublishingRunListener(SpringApplication application, String[] args) {
    // 设置前面创建的SpringApplication对象为其application属性值
   this.application = application;
    // 参数为空
   this.args = args;
    // 创建了一个简单应用程序的事件广播器
   this.initialMulticaster = new SimpleApplicationEventMulticaster();
   for (ApplicationListener<?> listener : application.getListeners()) {
       // 添加SpringApplication中的监听器,到广播器中
      this.initialMulticaster.addApplicationListener(listener);
   }
}

1.2 SpringApplicationRunListeners类的内部结构

class SpringApplicationRunListeners {
    private final Log log;
    private final List<SpringApplicationRunListener> listeners;
​
    SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log;
        this.listeners = new ArrayList(listeners);
    }
// XXX方法体内部都会遍历每一个监听器,然后调用相应的xxx方法,比如starting()方法的内部,,就会遍历每一个listeners中的每一个listener,调用其starting()方法
    void starting() {......}
​
    void environmentPrepared(ConfigurableEnvironment environment){......}
​
    void contextPrepared(ConfigurableApplicationContext context) {......}
​
    void contextLoaded(ConfigurableApplicationContext context) {......}
​
    void started(ConfigurableApplicationContext context) {......}
​
    void running(ConfigurableApplicationContext context){......}
​
    void failed(ConfigurableApplicationContext context, Throwable exception){......}
​
    private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context, Throwable exception){......}
}

2 EventPublishingRunListener#starting开启此事件发布监听器

@Override
public void starting() {
    // 2.1.将SpringApplicaiotn对象作为“事件源”,创建了ApplicationStartingEvent事件对象,每个事件对象中都存放着对“源”的引用,表明这些事件是发生在哪个对象上的
    // 2.2.对事件进行广播
    // 这就是使用了观察者模式
   this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
​
// 2.1 创建应用启动事件对象
public ApplicationStartingEvent(SpringApplication application, String[] args) {
        super(application, args);
    }
​
public SpringApplicationEvent(SpringApplication application, String[] args) {
        super(application);
        this.args = args;
    }
​
public ApplicationEvent(Object source) {
        super(source);
    }
​
public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");
​
        this.source = source;
    }

看一下,事件的继承关系图:

2.2 SimpleApplicationEventMulticaster#multicastEvent广播事件

public void multicastEvent(ApplicationEvent event) {
    // resolveDefaultEventType()方法,解析事件的类型,将时间类型封装在ResolvableType对象的type属性中
    this.multicastEvent(event, this.resolveDefaultEventType(event));
}
​
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
    Executor executor = this.getTaskExecutor();
    // 获取能够监听此type类型事件的监听器
    Iterator var5 = this.getApplicationListeners(event, type).iterator();
    // 遍历获取到的全部监听器,执行相应的监听方法
    while(var5.hasNext()) {
        ApplicationListener<?> listener = (ApplicationListener)var5.next();
        // 广播器中的执行器默认为null
        if (executor != null) {
            executor.execute(() -> {
                this.invokeListener(listener, event);
            });
        } else {
            // 调用监听器针对此event事件的相应的监听方法
            // 针对于不同类型的事件,监听器经过instanceof判断,会调用不同的方法
            // 此方法内部用会调用doInvokeListener()方法
            this.invokeListener(listener, event);
        }
    }
​
}

2.2.1 SimpleApplicationEventMulticaster#doInvokeListener

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        // 调用当前监听器的onApplicationEvent方法,判断事件类型,调用监听器的相对应方法
        listener.onApplicationEvent(event);
    } catch (ClassCastException var6) {
        String msg = var6.getMessage();
        if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
            throw var6;
        }
​
        Log logger = LogFactory.getLog(this.getClass());
        if (logger.isTraceEnabled()) {
            logger.trace("Non-matching event type for listener: " + listener, var6);
        }
    }
​
}

以RestartApplicationListener事件监听器为例

RestartApplicationListener#onApplicationEvent

public void onApplicationEvent(ApplicationEvent event) {
    // 判断监听器类型,调用相应方法,进行一些组件的初始化操作
    if (event instanceof ApplicationStartingEvent) {
        this.onApplicationStartingEvent((ApplicationStartingEvent)event);
    }
​
    if (event instanceof ApplicationPreparedEvent) {
        this.onApplicationPreparedEvent((ApplicationPreparedEvent)event);
    }
​
    if (event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) {
        Restarter.getInstance().finish();
    }
​
    if (event instanceof ApplicationFailedEvent) {
        this.onApplicationFailedEvent((ApplicationFailedEvent)event);
    }
​
}

3.SpringApplication#prepareEnvironment配置环境

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments) {
        // 3.1创建环境对象,依据不同的web应用类型创建不同的环境对象
     /**
               SERVLET  new StandardServletEnvironment();
               REACTIVE StandardReactiveWebEnvironment()
               NONE new StandardEnvironment()
     **/    
   ConfigurableEnvironment environment = getOrCreateEnvironment();
      //    配置环境(环境包括systemEnvironment、systemProperties、命令行参数commandLineArgs,servletContextInitParams、servletConfigInitParams,......)
   configureEnvironment(environment, applicationArguments.getSourceArgs());
   ConfigurationPropertySources.attach(environment);
    // 创建ApplicationEnvironmentPreparedEvent事件,遍历监听器调用对相应事件的监听方法(与前面SpringApplicationStart事件的流程一样),在ConfigFileApplicationListener监听器中会加载classpath下的配置文件中的内容到PropertySource中
   listeners.environmentPrepared(environment);
    // 将当前环境绑定到SpringAllication上
   bindToSpringApplication(environment);
   if (!this.isCustomEnvironment) {
      environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
            deduceEnvironmentClass());
   }
   ConfigurationPropertySources.attach(environment);
    // 返回环境对象
   return environment;
}

看一下配置好的环境对象:

可以看到index=6,已经加载了classpath:application.yml

4.SpringApplication#createApplicationContext

看一下有关applicationContext的继承关系图

protected ConfigurableApplicationContext createApplicationContext() {
   Class<?> contextClass = this.applicationContextClass;
   if (contextClass == null) {
      try {
       // 跟据web应用的类型创建相对应类型的应用上下文
         switch (this.webApplicationType) {
         case SERVLET:
       /**  
             "org.springframework.boot.web.servlet.context.
                AnnotationConfigServletWebServerApplicationContext"
        **/
            contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
            break;
         case REACTIVE:
         /**  
              "org.springframework.boot.web.reactive.context.
              AnnotationConfigReactiveWebServerApplicationContext"
        **/
            contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
            break;
         default:
       /**  
              "org.springframework.context.
              annotation.AnnotationConfigApplicationContext"
        **/
            contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
         }
      }
      catch (ClassNotFoundException ex) {
         throw new IllegalStateException(
               "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
      }
   }
    // 实例化应用上下文
    /**
        读过Spring源码的应该比较好理解,因为他与Spring中创建应用上下文流程基本相同
        1.调用AnnotationConfigServletWebServerApplicationContext的空参构造器,在它的空参构造器中最终又会调用父类GenericApplicationContext的空参构造器,在父类的空参构造器中,给当前的上下文new了一个beanFactory对象(DefaultListableBeanFactory)
        2.接下来会实例化一个阅读器,实例化阅读器时,又会做以下事情:
            注册一些内置的beanDefinition到bean工厂中(记住这个后置处理器【ConfigurationClassPostProcessor】、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor.....)       
        3.实例化一个扫描器,除非手动调用.scan其他基本用不到的   
    **/
   return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

5.SpringApplication#prepareContext

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
      SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    // 设置环境到应用上下文中
   context.setEnvironment(environment);
    // 进行一些后置处理:给beanFactory的conversionService属性设置值
   postProcessApplicationContext(context);
    // 遍历前面获取到的放在SpringApplication中的初始化器,调用初始化器的initialize方法,完成一些初始化操作(1.设置应用上下文的id 2、添加了几个beanFactory后置处理器 3.添加了一些对应用上下文的Listener )
   applyInitializers(context);
    // 创建ApplicationContextInitializedEvent事件,调用监听器相对应的监听方法(与前面相同)
   listeners.contextPrepared(context);
   if (this.logStartupInfo) {
      logStartupInfo(context.getParent() == null);
      logStartupProfileInfo(context);
   }
   // Add boot specific singleton beans
   ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    // 注册一个单例bean,到单例池中
   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
    // 获主启动类,就是我们编写的带有main方法的类
   Set<Object> sources = getAllSources();
   Assert.notEmpty(sources, "Sources must not be empty");
    // ===加载主启动类(注册主启动类的beanDefinition到bean工厂中)====
    /**
    1.判断启动类是不是符合条件的isEligible(source),只有以下都为false,才算满足条件,可以注册
    type.isAnonymousClass() 判断当前类型是不是匿名类
    isGroovyClosure(type) 判断是不是Groovy闭包
    hasNoConstructors(type) 判断构造器数组是不是空 
    **/
   load(context, sources.toArray(new Object[0]));
    /**
    1.将前面获取到的Listener都添加到应用上下文中(Set<ApplicationListener<?>> applicationListeners)
    2.如果listener实现了ApplicationContextAware接口,将它的ApplicationContext context属性设置为当前应用上下文
    3.遍历添加完成后,创建ApplicationPreparedEvent事件,广播事件(调用监听器的相对应事件的处理方法)
    **/
   listeners.contextLoaded(context);
}

重点来了

6.SpringApplication#refreshContext(具体细节结合具体问题后续分析)

在此方法内部经过一系列调用最终会调用到ConfigurableApplicationContext#refresh方法

protected void refresh(ConfigurableApplicationContext applicationContext) {
    // 调用了我们创建的应用上下文AnnotationConfigServletWebServerApplicationContext的刷新方法,在此方法内部又调用了父类AbstractApplicationContext的refresh()方法,所以说最终还是会与spring完成会合,--->在此方法中会完成,全部非懒加载的bean实例的创建工作
   applicationContext.refresh();
}

总结:spring boot应用启动的大体流程

如有问题欢迎指正.....

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值