• 欢迎访问 winrains 的个人网站!
  • 本网站主要从互联网整理和收集了与Java、网络安全、Linux等技术相关的文章,供学习和研究使用。如有侵权,请留言告知,谢谢!

SpringBoot 启动流程源码分析

Spring Boot winrains 来源:源码笔记 6个月前 (04-05) 32次浏览

1 概述

SpringApplication类用来启动Spring应用,默认会执行以下主要步骤来启动应用:

1),根据classpath创建一个相应的ApplicationContext
2),注册一个CommandLinePropertySource来曝光命令行参数作为spring属性
3),刷新application context来加载所有的单例bean
4),触发CommandLineRunner的bean实例的run方法

上面翻译自SpringApplication的官方注释。

2 SpringBoot的启动流程分析

2.0 启动SpringBoot

@SpringBootApplication
public class MvcApplication {

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

}

2.1 SpringApplication构造函数

因为SpringApplication.run(MvcApplication.class, args);方法时首先会new 一个SpringApplication对象,然后再执行其相应的run方法,所以先来看下SpringApplication的构造函数:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    // primarySources就是SpringApplication.run(MvcApplication.class, args);中的MvcApplication.class
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 根据不同的类路径来确定WebApplicationType
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    /**
     * 初始化 initializers 属性:
     * 从spring.factories配置文件中获得ApplicationContextInitializer接口的以下实现类并初始化到 initializers 属性中
     * # Application Context Initializers
     * org.springframework.context.ApplicationContextInitializer=\
     * org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
     * org.springframework.boot.context.ContextIdApplicationContextInitializer,\
     * ......
     */
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    /**
     * 初始化 listeners 属性:
     * 从spring.factories配置文件中获得ApplicationListener接口的以下实现类并初始化到 listeners 属性中
     * # Application Listeners
     * org.springframework.context.ApplicationListener=\
     * org.springframework.boot.ClearCachesApplicationListener,\
     * ......
     */
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 推断应用类型
    this.mainApplicationClass = deduceMainApplicationClass();
}

该构造函数主要是为一些变量属性赋值:

  • primarySources属性,即SpringApplication.run(MvcApplication.class, args);中传入的MvcApplication.class,该类为SpringBoot项目的启动类,主要从该类的configuration类加载bean
  • webApplicationType属性,代表应用类型,根据classpath存在的相应Application类来判断,详情请见2.1.1 deduceFromClasspath()方
  • initializers属性,ApplicationContextInitializer 数组,从spring.factories配置文件中加载,见2.1.2 getSpringFactoriesInstances(Class<T> type)方法。
  • listeners属性,ApplicationListener 数组,从spring.factories配置文件中加载
  • mainApplicationClass属性,获得哪个类调用了main(String[] args)方法,比如mainApplicationClass这里是“class com.jinyue.springboot.mvc.MvcApplication”启动了main方法,仅仅用来打印下日志

2.1.1 deduceFromClasspath()

static WebApplicationType deduceFromClasspath() {
   // 若classpath中不存在"org.springframework." + "web.servlet.DispatcherServlet"和"org.glassfish.jersey.servlet.ServletContainer"
   // 则返回WebApplicationType.REACTIVE,表明是reactive应用
   if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
         && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
      return WebApplicationType.REACTIVE;
   }
   // 若{ "javax.servlet.Servlet",
   //       "org.springframework.web.context.ConfigurableWebApplicationContext" }
   // 都不存在在classpath,则说明是不是web应用
   for (String className : SERVLET_INDICATOR_CLASSES) {
      if (!ClassUtils.isPresent(className, null)) {
         return WebApplicationType.NONE;
      }
   }
   // 最终返回普通的web应用
   return WebApplicationType.SERVLET;
}

根据classpath判断应用类型,通过反射加载classpath判断指定的标志类存在与否来分别判断是reactive应用,web应用还是非web应用。

2.1.2 getSpringFactoriesInstances(Class type)

// 返回spring.factories中获取类名并创建的对象
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    // Use names and ensure unique to protect against duplicates
    // 加载指定类型对应的,在 `META-INF/spring.factories` 里的类名的数组
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 根据 `META-INF/spring.factories` 里获取的类型创建相应的对象
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    // 排序
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

先根据接口类从项目的所有spring.factories配置文件中获得相应的具体实现类放入names集合,然后再调用createSpringFactoriesInstances方法创建具体的实例,下面是createSpringFactoriesInstances方法:

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
        ClassLoader classLoader, Object[] args, Set<String> names) {
    // 先创建ArrayList集合,大小即为names的大小
    List<T> instances = new ArrayList<>(names.size());
    // 遍历
    for (String name : names) {
        try {
            // 根据name通过反射获得相应的类
            Class<?> instanceClass = ClassUtils.forName(name, classLoader);
            Assert.isAssignable(type, instanceClass);
            // 获得构造器
            Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
            // new 出一个对象来
            T instance = (T) BeanUtils.instantiateClass(constructor, args);
            // 将对象添加instances集合中
            instances.add(instance);
        }
        catch (Throwable ex) {
            throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
        }
    }
    return instances;
}

根据传入的接口类型从spring.factories配置文件中加载相应的实例,比如:getSpringFactoriesInstances(ApplicationContextInitializer.class)方法根据ApplicationContextInitializer.class接口类去spring.factories配置文件寻找具体实现类,最终初始化到初始化 initializers 属性中,经过调试,ApplicationContextInitializer接口具体实现类有:

而ApplicationListener的具体实现类如下:

2.2 SpringApplication的run(String… args)启动函数分析

前面分析了SpringApplication的构造函数,下面来分析该类的run方法。

public static void main(String[] args) throws Exception {
   SpringApplication.run(new Class<?>[0], args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
   // 新建SpringApplication对象,再调用run方法
   return new SpringApplication(primarySources).run(args);
}
public ConfigurableApplicationContext run(String... args) {
   // stopWatch用于统计run启动过程时长
   StopWatch stopWatch = new StopWatch();
   // 开始计时
   stopWatch.start();
   // 创建ConfigurableApplicationContext对象
   ConfigurableApplicationContext context = null;
   // exceptionReporters集合用来存储SpringApplication启动过程的异常,SpringBootExceptionReporter且通过spring.factories方式来加载
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   // 配置headless属性
   configureHeadlessProperty();
   /**
    * 从spring.factories配置文件中加载到EventPublishingRunListener对象并赋值给SpringApplicationRunListeners
    * # Run Listeners
    * org.springframework.boot.SpringApplicationRunListener=\
    * org.springframework.boot.context.event.EventPublishingRunListener
    */
   SpringApplicationRunListeners listeners = getRunListeners(args);
   // 启动SpringApplicationRunListeners监听
   listeners.starting();
   try {
      // 创建ApplicationArguments对象,封装了args参数
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      // 备配置参数有app.properties,外部配置参数比如jvm启动参数等
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      // 配置spring.beaninfo.ignore属性
      configureIgnoreBeanInfo(environment);
      // 打印springboot的bannner
      Banner printedBanner = printBanner(environment);
      // 根据不同类型创建不同类型的spring applicationcontext容器
      context = createApplicationContext();
      /**
       * 异常报告
       * 从spring.factories配置文件中加载exceptionReporters,其中ConfigurableApplicationContext.class作为FailureAnalyzers构造方法的参数
       * # Error Reporters
       * org.springframework.boot.SpringBootExceptionReporter=\
       * org.springframework.boot.diagnostics.FailureAnalyzers
       */
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      // 准备容器事项:调用各个ApplicationContextInitializer的initialize方法
      // 和触发SpringApplicationRunListeners的contextPrepared及contextLoaded方法等
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      // 刷新容器,这一步至关重要
      refreshContext(context);
      // 执行刷新容器后的后置处理逻辑,注意这里为空方法
      afterRefresh(context, applicationArguments);
      // 停止stopWatch计时
      stopWatch.stop();
      // 打印springboot的启动时常
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
      }
      // 触发SpringApplicationRunListener的started方法,通知spring容器已经启动
      listeners.started(context);
      // 调用ApplicationRunner和CommandLineRunner的run方法,实现spring容器启动后需要做的一些东西
      callRunners(context, applicationArguments);
   }
   // 若上面的方法抛出异常,将异常添加到exceptionReporters集合中,并抛出 IllegalStateException 异常。
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, listeners);
      throw new IllegalStateException(ex);
   }

   try {
      // 当容器刷新完毕等,触发SpringApplicationRunListeners数组的running方法
      listeners.running(context);
   }
   catch (Throwable ex) {
      // 若上面的方法抛出异常,将异常添加到exceptionReporters集合中,并抛出 IllegalStateException 异常。
      handleRunFailure(context, ex, exceptionReporters, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

上面的run方法比较长,下面捋一下,现在将run方法关键做的事情总结如下:

1,利用stopWatch用于统计run启动过程时长

2,调用configureHeadlessProperty()方法配置headless即“java.awt.headless”属性,默认为ture,那么:做了这样的操作后,SpringBoot想干什么呢?

其实是想设置该应用程序,即使没有检测到显示器,也允许其启动.对于服务器来说,是不需要显示器的,所以要这样设置.

参考:http://www.cnblogs.com/wangxuejian…

3,获取SpringApplicationRunListeners,并启动SpringApplicationRunListener的监听,此时利用EventPublishingRunListener

的initialMulticaster对象来发布ApplicationStartingEvent事件,表示SpringApplication开始启动,监听ApplicationStartingEvent事件的listeners们将会执行相应逻辑。

注意:1)EventPublishingRunListener拥有SpringApplication属性。

4,调用prepareEnvironment方法准备environment,比如准备配置参数有servlet配置参数,外部配置参数比如jvm启动参数等。详情请见2.2.1 prepareEnvironment方法。

5,调用printBanner(environment)方法打印springboot的bannner

6,调用createApplicationContext()方法根据webApplicationType创建容器context,因为是web项目,这里创建的是AnnotationConfigServletWebServerApplicationContext容器对象,详情请见2.2.2 createApplicationContext方法

7,调用getSpringFactoriesInstances方法创建exceptionReporters集合,该集合用于收集springboot启动时的异常。

  • 该exceptionReporters集合只有一个FailureAnalyzers对象,但是FailureAnalyzers又有17个FailureAnalyzer个具体实现类,如下图:

8,调用prepareContext方法准备容器事项,比如调用调用各个ApplicationContextInitializer的initialize初始化方法
和触发SpringApplicationRunListeners的contextPrepared及contextLoaded方法等,详情请见2.2.3 prepareContext方法

9,调用refreshContext方法最终调用AbstractApplicatioinContetext.refresh()方法刷新容器,这一步至关重要,因为很多spring重要的逻辑都在这里处理,请见2.2.4 refreshContext方法

10,调用afterRefresh方法执行刷新容器后的后置处理逻辑,注意目前这里为空方法,留给子类去实现。

11,触发SpringApplicationRunListener的started方法,发布ApplicationStartedEvent事件,通知spring容器已经启动,相应listener监听该事件执行相应处理逻辑。

12,调用callRunners方法,即会调用ApplicationRunner和CommandLineRunner的run方法,实现spring容器启动后需要做的一些东西,详情请见2.2.5 callRunners方法

2.2.1 prepareEnvironment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    // Create and configure the environment
    /**
     * 根据webApplicationType创建不同类型的ConfigurableEnvironment对象:
     * 		case SERVLET:
     * 			return new StandardServletEnvironment();
     * 		case REACTIVE:
     * 			return new StandardReactiveWebEnvironment();
     * 		default:
     * 			return new StandardEnvironment();
     *
     * 比如servlet的初始化标签<servletContextInitParams />
     */
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 对创建的environment进行配置
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    // 将environment最终封装到PropertySource对象中
    ConfigurationPropertySources.attach(environment);
    // 通知 SpringApplicationRunListener 的数组,环境变量已经准备完成
    listeners.environmentPrepared(environment);
    // 为SpringApplication绑定环境变量environment
    bindToSpringApplication(environment);
    // 如果不是自定义的化境变量,若有必要则进行转换
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                deduceEnvironmentClass());
    }
    // 如果有 attach 到 environment 上的 MutablePropertySources ,则添加到 environment 的 PropertySource 中。
    ConfigurationPropertySources.attach(environment);
    return environment;
}

上面代码首先根据webApplicationType创建不同的environment对象,这里创建的是StandardServletEnvironment对象;然后对environment对象进行配置,比如增加 environment 的 PropertySource 属性源,还有配置哪个profile为actived;environment环境变量准备好后,此时发布ApplicationEnvironmentPreparedEvent事件,执行environment准备好后的相关逻辑;然后再将environment绑定到SpringApplication,对非自定义的envoronment进行转换等。

2.2.2 createApplicationContext

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.2.3 prepareContext

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
        SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    // 设置context的environment属性
    context.setEnvironment(environment);
    // 根据情况对ApplicationContext应用一些相关的后置处理,比如设置resourceLoader属性等
    postProcessApplicationContext(context);
    // 在容器刷新前调用ApplicationContextInitializer的初始化方法
    applyInitializers(context);
    // 在sources加载前,一旦context容器被创建且已准备好,会触发该事件方法通知容器已经准备好
    listeners.contextPrepared(context);
    // 打印启动相关日志
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        /**
         * 此处打印的日志如下:
         * ....MVCApplication  : The following profiles are active: prod
         */
        logStartupProfileInfo(context);
    }
    // Add boot specific singleton beans
    // 得到beanFactory
    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);
    }
    // Load the sources
    // 加载BeanDefinition等,这里应该是JavaConfig上的一些定义的bean
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    // 加载bean到application context.
    load(context, sources.toArray(new Object[0]));
    // 在context容器刷新前,一旦容器被加载就会触发调用该方法,通知spring容器已经加载完成
    listeners.contextLoaded(context);
}

prepareContext主要是准备context,主要做了以下事情:

  • postProcessApplicationContext(context),子类可以覆盖该方法做一些定制处理
  • applyInitializers(context):这个是将之前从spring.factories中加载的ApplicationContextInitializer接口的具体实现类逐个应用其initialize初始化方法,执行一些初始化逻辑

  • listeners.contextPrepared(context):发布ApplicationContextInitializedEvent事件,说明context已经准备好
  • getAllSources():将primarySource加载出来,应该是之后要对其配置的javaconfig或xml配置的bean进行加载,这里留个疑问先。
  • load(context, sources.toArray(new Object[0])):加载所有的配置文件比如javaconfig和xml配置文件的bean定义,这里创建了一个BeanDefinitionLoader对象;BeanDefinitionLoader作为AnnotatedBeanDefinitionReader,XmlBeanDefinitionReader和ClassPathBeanDefinitionScanner的门面,从底层源加载bean定义
  • listeners.contextLoaded(context):发布ApplicationPreparedEvent,说明context已经加载完毕。

2.2.4 refreshContext

/**
 * 刷新容器
 * @param context
 */
private void refreshContext(ConfigurableApplicationContext context) {
    // 刷新容器
    refresh(context);
    // 若注册了shutdownHook钩子,则注册shutdownHook钩子
    // JVM shutdownHook的作用是当jvm关闭时,关闭context容器,销毁相关bean
    if (this.registerShutdownHook) {
        try {
            context.registerShutdownHook();
        }
        catch (AccessControlException ex) {
            // Not allowed in some environments.
        }
    }
}


protected void refresh(ApplicationContext applicationContext) {
    // 断言:applicationContext必须是AbstractApplicationContext的子类,否则报错
    Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    // 刷新容器
    ((AbstractApplicationContext) applicationContext).refresh();
}



public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        // 在context刷新前做一些准备工作,比如设置context的启动日期,active flag和property sources的初始化工作
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        // 让子类刷新其内部bean factory,实质就是再新建一个DefaultListableBeanFactory类型的bean factory对象
        // 加载xml配置的bean定义,注意加载annotation的bean定义应该是在invokeBeanFactoryPostProcessors方法中加载??
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        // 上面那一步工厂刚建好,什么都没有,因此需要准备一些配置,
        // 比如配置factory的标准容器特性,比如容器的类加载器和一些后置处理器比如ApplicationContextAwareProcessor 等
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            // 在经过上面的标准初始化后,修改应用容器的内部bean factory。
            // 在这一步,所有的bean definitions将会被加载,但此时bean还不会被实例化
            // 此时会注册一些BeanPostProcessors
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            // Bean工厂的后置处理器的相关逻辑,BeanFactoryPostProcessor(触发时机:bean定义注册之后bean实例化之前)
            // 和BeanDefinitionRegistryPostProcessor(触发时机:bean定义注册之前),所以可以在Bean工厂的后置处理器中修改Bean的定义信息,
            // 比如是否延迟加载、加入一些新的Bean的定义信息等实例化所有注册的BeanFactoryPostProcessor beans,并且调用其后置处理方法
            // BeanFactoryPostProcessor 是针对 BeanFactory 的扩展,主要用在 bean 实例化之前,读取 bean 的定义,并可以修改它。
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // 实例化并注册所有Bean的后置处理器:BeanPostProcessor beans,册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。
            // registerBeanPostProcessors 方法主要用于处理 BeanPostProcessor 接口,调用时机:必须在所有bean的实例化之前调用
            // BeanPostProcessor 是针对 bean 的扩展,主要用在 bean 实例化之后,执行初始化方法前后,允许开发者对 bean 实例进行修改。
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            // 这里的逻辑主要跟国际化有关
            initMessageSource();

            // Initialize event multicaster for this context.
            // 初始化事件广播器,如果自定义了广播器,就用自定义的,
            // 如果没有自定义就用默认得SimpleApplicationEventMulticaster广播器。并且把广播器设置到上下文的applicationEventMulticaster属性中。
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            // 这个是个模板方法,留给子类实现,在特殊的bean初始化之前和单例bean实例化之前调用
            // 这里应该可以扩展ThemeSource接口
            onRefresh();

            // Check for listener beans and register them.
            // 注册实现了ApplicationListener接口的监听器,这里不会影响其他监听器的使用
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            // 完成容器bean factory的初始化,并初始化所有剩余的单例bean
            // 这个方法在容器刷新过程中非常重要,因为所有的bean,如果不是lazy-init的都会在这一步进行实例化,并且做一些处理。
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            // 完成容器的刷新共工作,并且调用生命周期处理器的onRefresh()方法,并且发布ContextRefreshedEvent事件
            finishRefresh();
        }

        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }

            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();

            // Reset 'active' flag.
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

refresh方法是spring容器的重头戏,很多重要复杂的逻辑都在这里实现。

比如所有beanFactory的创建,所有bean定义的加载,实例化,注册一些事件监听器比如实现了ApplicationListener接口的监听器,还有一些后置处理方法也在这里处理,下面主要讲下后置处理方法,beanFactoryPostProcessor和beanPostProcessor等后置处理器也在这里实现调用相应的后置处理方法,比如beanFactoryPostProcessor是bean工厂的bean属性处理容器,说通俗一些就是可以管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以随心所欲的修改属性;BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口,通过该接口的postProcessBeforeInitialization和postProcessAfterInitialization方法可以在bean的初始化前后执行一些自定义的逻辑。

2.2.5 callRunners

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);
        }
    }
}

3 总结

目前springboot的启动流程分析就已经结束了,第一次写源码解析的博文,参考了很多文章,且写的巨慢。。。

由于作者水平有限,若写的有错误的地方还请评论纠正, 不胜感激,谢谢。

参考:

1,http://www.cnblogs.com/youzhibing/…

2,blog.csdn.net/yhahaha_/ar…

3,blog.csdn.net/lz710117239…

4,http://www.cnblogs.com/youzhibing/…

5,http://www.jianshu.com/p/fca013ec1…

6,http://www.cnblogs.com/toby-xu/p/1…

7,blog.csdn.net/v123411739/…

作者:源码笔记

来源:https://juejin.im/post/5e3fbbabf265da574111f4cb


版权声明:文末如注明作者和来源,则表示本文系转载,版权为原作者所有 | 本文如有侵权,请及时联系,承诺在收到消息后第一时间删除 | 如转载本文,请注明原文链接。
喜欢 (0)