SpringApplication到底run了什么(下)

谁践踏了优雅 2023-08-17 15:28 140阅读 0赞

在上篇文章中SpringApplication到底run了什么(上)中,我们分析了下面这个run方法的前半部分,本篇文章继续开工








  1. 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
  1. public ConfigurableApplicationContext run(String args) {

    //。。。
    //接上文继续
    configureIgnoreBeanInfo(environment);
    Banner printedBanner = printBanner(environment);
    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, listeners, exceptionReporters, ex);
    throw new IllegalStateException(ex);
    }
    listeners.running(context);
    return context;
    }
  1. 获取系统属性spring.beaninfo.ignore







  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
  1. private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {

    if (System.getProperty(
    CachedIntrospectionResults.spring.beaninfo.ignore) == null) {

    Boolean ignore = environment.getProperty(spring.beaninfo.ignore,
    Boolean.class, Boolean.TRUE);
    System.setProperty(CachedIntrospectionResults.spring.beaninfo.ignore,
    ignore.toString());
    }
    }

但是这个属性的作用还真不知道。。

  1. 打印banner
  2. 根据当前环境创建ApplicationContext







  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
  1. protected ConfigurableApplicationContext createApplicationContext() {

    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {

    try {

    switch (this.webApplicationType) {

    case SERVLET:
    contextClass = Class.forName(DEFAULT_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);
    }

基于咱们的Servlet环境,所以创建的ApplicationContext为AnnotationConfigServletWebServerApplicationContext

  1. 加载SpringBootExceptionReporter,这个类里包含了SpringBoot启动失败后异常处理相关的组件







  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  1. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
    Class<?>[] parameterTypes, Object args) {

    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    Set<String> names = new LinkedHashSet<>(
    SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
    classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
    }

10 prepareContext 这一块还是比较长的








  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
  1. 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);
    }

    // Load the sources
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, Sources must not be empty);
    load(context, sources.toArray(new Object[0]));
    listeners.contextLoaded(context);
    }
  1. 1. 第一行,将context中相关的environment全部替换







  1. 1
    2
    3
    4
    5
    6

  1. public void setEnvironment(ConfigurableEnvironment environment) {

    super.setEnvironment(environment); // 设置context的environment
    this.reader.setEnvironment(environment); // 实例化context的reader属性的conditionEvaluator属性
    this.scanner.setEnvironment(environment); // 设置context的scanner属性的environment属性
    }
  1. 2. 上下文后处理







  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

  1. protected void postProcessApplicationContext(ConfigurableApplicationContext context) {

    if (this.beanNameGenerator != null) {

    context.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());
    }
    }
    }

这一块默认beanNameGeneratorresourceLoader都是空的,只有当我们自定义这两个对象时才会把容器内的bean替换

  1. 执行所有的ApplicationContextInitializerinitialize方法







  1. 1
    2
    3
    4
    5
    6
    7
    8
    9

  1. 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);
    }
    }
  1. 4. `listeners.contextPrepared(context)`这是个空方法,没有实现,一个Spring的扩展点
  2. 5. 打印profile
  3. 6. 注册bean`springApplicationArguments`
  4. 7. 发布事件







  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  1. public void contextLoaded(ConfigurableApplicationContext context) {

    for (ApplicationListener<?> listener : this.application.getListeners()) {

    if (listener instanceof ApplicationContextAware) {

    ((ApplicationContextAware) listener).setApplicationContext(context);
    }
    context.addApplicationListener(listener);
    }
    this.initialMulticaster.multicastEvent(
    new ApplicationPreparedEvent(this.application, this.args, context));
    }

这里不仅发布了ApplicationPreparedEvent事件,还往实现了ApplicationContextAware接口的监听器中注入了context容器

  1. load,其实就是创建了一个BeanDefinitionLoader对象







  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
  1. protected void load(ApplicationContext context, Object[] sources) {

    if (logger.isDebugEnabled()) {

    logger.debug(
    Loading source + StringUtils.arrayToCommaDelimitedString(sources));
    }
    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);
    }
    loader.load();
    }
  1. 容器的初始化refreshContext
    这个方法最后还是调用的AbstractApplicationContext类的refresh方法,由于篇幅过长这里就不展开了,感兴趣的同学可以参考这篇文章:基于注解的SpringIOC源码解析







  1. 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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
  1. public void refresh() throws BeansException, IllegalStateException {

    synchronized (this.startupShutdownMonitor) {

    // 记录容器的启动时间、标记“已启动”状态、检查环境变量
    prepareRefresh();
    // 初始化BeanFactory容器、注册BeanDefinition
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
    prepareBeanFactory(beanFactory);
    try {

    // 扩展点
    postProcessBeanFactory(beanFactory);
    // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
    invokeBeanFactoryPostProcessors(beanFactory);
    // 注册 BeanPostProcessor 的实现类
    registerBeanPostProcessors(beanFactory);
    // 初始化MessageSource
    initMessageSource();
    // 初始化事件广播器
    initApplicationEventMulticaster();
    // 扩展点
    onRefresh();
    // 注册事件监听器
    registerListeners();
    // 初始化所有的 singleton beans
    finishBeanFactoryInitialization(beanFactory);
    // 广播事件
    finishRefresh();
    }
    catch (BeansException ex) {

    if (logger.isWarnEnabled()) {

    logger.warn(Exception encountered during context initialization - +
    cancelling refresh attempt: + ex);
    }
    // 销毁已经初始化的的Bean
    destroyBeans();
    // 设置 ‘active’ 状态
    cancelRefresh(ex);
    throw ex;
    }
    finally {

    // 清除缓存
    resetCommonCaches();
    }
    }
    }
  1. afterRefresh
    这里没有任何实现,Spring留给我们的扩展点
  2. 停止之前启动的计时装置,然后发送ApplicationStartedEvent事件
  3. 调用系统中ApplicationRunner以及CommandLineRunner接口的实现类,关于这两个接口的使用可以参考我的这篇文章:Java项目启动时执行指定方法的几种方式







  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  1. private void callRunners(ApplicationContext context, ApplicationArguments args) {

    List<Object> 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);
    }
    }
    }
  1. 异常处理
  2. 发送ApplicationReadyEvent事件

往期好文

640?wx\_fmt=png

如果文章对您有所帮助,收藏、转发、在看安排一下!!!

发表评论

表情:
评论列表 (有 0 条评论,140人围观)

还没有评论,来说两句吧...

相关阅读