所有分类
  • 所有分类
  • 未分类

SpringBoot原理-启动流程

简介

本文介绍SpringBoot的启动流程。

分析Spring的启动流程有多种方法:1.构造一个 AnnotationConfigApplicationContext对象,调用它的getBean(xxx.class)方法; 2.直接分析SpringBoot的启动流程。

本文直接分析SpringBoot的启动流程。本文分析的版本:SpringBoot版本:2.3.0.RELEASE(其对应Spring:5.2.6.RELEASE)。

总流程概述

简介

  1. 从spring.factories配置文件中加载EventPublishingRunListener对象
    1. 该对象有SimpleApplicationEventMulticaster属性,它在SpringBoot启动过程的不同阶段用来发射内置的生命周期事件;
      spring.factories位置:spring-boot-2.3.0.RELEASE.jar。
          本处用到的是:
             org.springframework.boot.SpringApplicationRunListener=\
             org.springframework.boot.context.event.EventPublishingRunListener
  2. 准备环境变量(Environment)
    1. 包括系统变量,环境变量,命令行参数,默认变量,servlet相关配置变量,随机值以及配置文件(比如application.properties)等;
  3. 打印SpringBoot的banner标志
  4. 根据不同类型环境创建不同类型的ApplicationContext容器
    1. 因为这里是servlet环境,所以创建的是AnnotationConfigServletWebServerApplicationContext容器对象;
  5. 加载报告SpringBoot启动过程中的异常的对象
    1. 从spring.factories配置文件中加载FailureAnalyzers对象,
  6. 为刚创建的容器对象做一些初始化工作,准备一些容器属性值等;
    1. 对ApplicationContext调用一些相关的后置处理
    2. 调用各个ApplicationContextInitializer的初始化方法来执行一些初始化逻辑等;
  7. 刷新容器。这一步至关重要
    1. 调用BeanFactoryPostProcessor(BeanFactory的后置处理器))
    2. 注册并实例化BeanPostProcessor(bean的后置处理器)
    3. 初始化事件广播器(用于发布事件)
    4. 注册事件监听器(用于接收事件)
      1. 注册实现了ApplicationListener的bean
    5. 初始化其余的单例bean(调用到BeanPostProcessor)
      1. “其余的”的含义:BeanPostProcessor之外的bean,因为BeanPostProcessor在前边已经实例化,此处不再处理。
    6. 结束refresh
      1. 清除缓存(比如扫描到的ASM元数据信息)
      2. 初始化LifecycleProcessor并调用它的onRefresh()方法
      3. 发布刷新结束事件
  8. 执行刷新容器后的后置处理逻辑,注意这里为空方法;
  9. 调用ApplicationRunner和CommandLineRunner的run方法
    1. 我们实现这两个接口可以在Spring容器启动后执行一些操作
  10. 报告启动异常
    1. 若启动过程中抛出异常,此时用FailureAnalyzers来报告异常;
  11. 最终返回容器对象,这里调用方法没有声明对象来接收。

源码分析

SpringApplication.run(DemoApplication.class, args);    //DemoApplication.class
    run(new Class[]{primarySource}, args);                         //SpringApplication.class
        (new SpringApplication(primarySources)).run(args);    //SpringApplication.class
                public ConfigurableApplicationContext run(String… args) //SpringApplication.class

public ConfigurableApplicationContext run(String... args) {
    // new 一个StopWatch用于统计run启动过程花了多少时间
    StopWatch stopWatch = new StopWatch();

    // 开始计时
    stopWatch.start();

    ConfigurableApplicationContext context = null;

    // exceptionReporters集合存储异常报告器,用来报告SpringBoot启动过程的异常
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();

    // 配置“java.awt.headless”属性,默认true。即:即使没有检测到显示器,也允许其启动。
    // 对于服务器来说,是不需要显示器的,所以要这样设置.
    this.configureHeadlessProperty();

    // 【1】从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化,然后赋值
    //      给SpringApplicationRunListeners。目前里边只有:EventPublishingRunListener,
    //      它发射SpringBoot启动过程中内置的生命周期事件,标志不同启动阶段
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    
    //发布【ApplicationStartingEvent】事件。
    listeners.starting();

    Collection exceptionReporters;
    try {
        // 创建ApplicationArguments对象,封装了args参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        
        // 【2】准备环境变量:系统变量,环境变量,命令行参数,默认变量,servlet相关配置变量,随机值,
        //       JNDI属性值,以及配置文件(比如application.properties)等,注意这些环境变量是有优先级的
        //       发布【ApplicationEnvironmentPreparedEvent】事件
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
        
        // 配置spring.beaninfo.ignore属性,默认为true,即跳过搜索BeanInfo classes.
        this.configureIgnoreBeanInfo(environment);
        
        // 【3】控制台打印SpringBoot的banner标志
        Banner printedBanner = this.printBanner(environment);
        
        // 【4】创建不同类型的Spring ApplicationContext容器(根据类型)
        //    这里我引入web包,所以创建的是AnnotationConfigServletWebServerApplicationContext容器对象
        context = this.createApplicationContext();
        
        // 【5】从spring.factories中加载异常报告器实例,这里加载的是FailureAnalyzers。
        //    FailureAnalyzers构造参数为ConfigurableApplicationContext,因为要获取beanFactory和environment
        exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, 
              new Class[]{ConfigurableApplicationContext.class}, context);
        
        // 【6】为刚创建的容器对象做一些初始化工作,准备一些容器属性值等
        // 1)为容器对象的属性AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner设置environgment属性
        // 2)根据情况对ApplicationContext应用一些相关的后置处理,比如设置resourceLoader属性等
        // 3)容器刷新前调用各个ApplicationContextInitializer的初始化方法,ApplicationContextInitializer是在
        //       构建SpringApplication对象时从spring.factories中加载的
        // 4)发布【ApplicationContextInitializedEvent】事件。标志context容器被创建且已准备好
        // 5)从context容器获取beanFactory,向beanFactory中注册一些单例bean,比如applicationArguments,printedBanner
        // 6)TODO 加载bean到application context,注意这里只是加载了部分bean比如mainApplication这个bean,
        //        猜测:大部分bean是在AbstractApplicationContext.refresh方法中被加载
        // 7)发布【ApplicationPreparedEvent】事件。标志Context容器已经准备完成
        this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        
        // 【7】刷新容器,这一步至关重要,主要做了以下工作:
        // 1)在context刷新前做一些准备工作,比如初始化一些属性设置,属性合法性校验和保存容器中的一些早期事件等;
        // 2)让子类刷新其内部bean factory,注意SpringBoot和Spring启动的情况执行逻辑不一样
        // 3)对bean factory进行配置,比如配置bean factory的类加载器,后置处理器等
        // 4)准备完bean factory后,执行后置处理逻辑,子类重写此方法在BeanFactory创建并预准备完成后做进一步设置
        //        在这一步,所有的bean definitions将会被加载,但此时bean还不会被实例化
        // 5)执行BeanFactoryPostProcessor的方法即调用bean factory的后置处理器:
        //         BeanDefinitionRegistryPostProcessor(触发时机:bean定义的注册之前)
        //         BeanFactoryPostProcessor(触发时机:bean定义的注册之后,bean实例化之前)
        // 6)注册bean后置处理器BeanPostProcessor。不同接口类型的BeanPostProcessor在Bean创建前后的执行时机不一样
        // 7)初始化国际化MessageSource相关的组件,比如消息绑定,消息解析等
        // 8)初始化事件广播器,若bean factory没包含事件广播器,
        //        则new一个SimpleApplicationEventMulticaster广播器对象并注册到bean factory中
        // 9)AbstractApplicationContext定义了一个模板方法onRefresh,留给子类覆写。
        //        比如ServletWebServerApplicationContext覆写了该方法来创建内嵌的tomcat容器
        // 10)注册ApplicationListener接口的实现类,之前已经有了事件广播器,此时即可发布early application events
        // 11)完成容器bean factory的初始化,并初始化所有剩余的单例bean。
        //        这一步非常重要,一些BeanPostProcessor会在这里调用。
        // 12)完成容器的刷新工作,并且调用生命周期处理器的onRefresh()方法,并且发布ContextRefreshedEvent事件
        this.refreshContext(context);
        
        // 【8】执行刷新容器后的后置处理逻辑。目前这里为空方法
        this.afterRefresh(context, applicationArguments);
        
        // 停止stopWatch计时
        stopWatch.stop();
        
        // 打印日志
        if (this.logStartupInfo) {
            (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
        }

        // 发布【ApplicationStartedEvent】事件。标志spring容器已经刷新,此时所有的bean实例都已经加载完毕
        listeners.started(context);
        
        // 【9】调用ApplicationRunner和CommandLineRunner的run方法。        
        this.callRunners(context, applicationArguments);
    } catch (Throwable var10) {
        // 【10】若启动过程中抛出异常,此时用FailureAnalyzers来报告异常
        // 并发布【ApplicationFailedEvent】事件,标志SpringBoot启动失败
        this.handleRunFailure(context, var10, exceptionReporters, listeners);
        throw new IllegalStateException(var10);
    }

    try {
        // 发布【ApplicationReadyEvent】事件。标志SpringApplication已在运行(即已经成功启动),可以接收服务请求了。
        listeners.running(context);
        // 【11】最终返回容器
        return context;
    } catch (Throwable var9) {
        // 若出现异常,此时仅仅报告异常,而不会发射任何事件
        this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
        throw new IllegalStateException(var9);
    }
}

refresh()简述

在上边“总流程概述”中,this.refreshContext(context);是关键,追踪它:

this.refreshContext(context);  //SpringApplication.class
    this.refresh((ApplicationContext)context); // SpringApplication.class
        this.refresh((ConfigurableApplicationContext)applicationContext); //SpringApplication.class
            applicationContext.refresh(); // SpringApplication.class
                void refresh(); // ConfigurableApplicationContext.class(这是个接口)
                    void refresh(); // AbstractApplicationContext.class(这是个抽象类,实现了上边接口)
                        //下边是上边抽象类的两个子类,但它们都没覆写refresh(),只调用了抽象类的refresh()
                        final void refresh() // ServletWebServerApplicationContext.class
                        final void refresh() // ReactiveWebServerApplicationContext.class

所以,我们只需关注于:AbstractApplicationContext#refresh()

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        //容器刷新前的准备:设置上下文状态,获取属性,验证必要的属性等
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        // 获取新的beanFactory,销毁原有beanFactory、为每个bean生成BeanDefinition等。
        //    注意,此处是获取新的,销毁旧的,这就是刷新的意义
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        // 配置beanFactory:设置BeanPostProcessor、ClassLoader,SpEL表达式解析器等
        //   BeanPostProcessor:ApplicationContextAwareProcessor和ApplicationListenerDetector
        //      前者:它回调实现了ApplicationContextAware的类的setApplicationContext()方法,
        //      后者:将ApplicationListener的实现类bean加入到监听器列表中
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            // 空方法,允许在子类中对beanFactory进行后置处理。
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            // 实例化并调用所有注册的beanFactory后置处理器(实现接口BeanFactoryPostProcessor的bean)。
            // 在beanFactory标准初始化之后执行  例如:PropertyPlaceholderConfigurer(处理占位符)
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // 注册并实例化BeanPostProcessor的实现类。
            //     因为里面调用了getBean()方法,所以实际也会实例化BeanPostProcessor
            // 例如:
            //    AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)
            //    RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法)
            //    CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等。
            //    自定义的BeabPostProcessor
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            // 初始化国际化工具类MessageSource
            initMessageSource();

            // Initialize event multicaster for this context.
            // 初始化事件广播器
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            // 模板方法,在容器刷新的时候可以自定义逻辑(子类自己去实现逻辑),不同的Spring容器做不同的事情
            onRefresh();

            // Check for listener beans and register them.
            // 注册监听器,并且广播early application events,也就是早期的事件
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            // 实例化所有剩余的(非懒加载)单例Bean(我们自定义的Bean)。此时各种BeanPostProcessor起作用。
            //    比如invokeBeanFactoryPostProcessors方法中根据各种注解解析出来的类,在这时被初始化       
            //    为什么说是剩余呢?若开发人员自定义了BeanPostProcessor,它在前面已实例化,所以这里不会再实例化
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            // refresh做完之后需要做的其他事情
            //    清除上下文资源缓存(如扫描中的ASM元数据)
            //    初始化上下文的生命周期处理器,并刷新(找出Lifecycle接口的实现类(bean)并执行其onRefresh()方法。
            //    发布ContextRefreshedEvent事件告知对应的ApplicationListener进行相应操作
            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.
            //如果刷新失败那么就会将已经创建好的单例Bean销毁掉
            destroyBeans();

            // Reset 'active' flag.
            //重置context的活动状态 告知是失败的
            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...
            // 失败与否,都会重置Spring内核的缓存。因为可能不再需要metadata给单例Bean了。
            resetCommonCaches();
        }
    }
}

refresh()详述

AbstractApplicationContext#refresh()

在refresh()方法中,比较重要的方法为invokeBeanFactoryPostProcessors(beanFactory) 和 finishBeanFactoryInitialization(beanFactory)。其他方法都比较简单。 

prepareRefresh()

概述

容器刷新前的准备:设置上下文状态,获取属性,验证必要的属性等

位于:AbstractApplicationContext类

	protected void prepareRefresh() {
		//记录容器启动时间,然后设立对应的标志位
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);

		// 打印info日志:开始刷新this此容器了
		if (logger.isInfoEnabled()) {
			logger.info("Refreshing " + this);
		}

		// Initialize any placeholder property sources in the context environment
		// 这是扩展方法,由子类去实现,可以在验证之前为系统属性设置一些值可以在子类中实现此方法
		// 因为我们这边是AnnotationConfigApplicationContext,可以看到不管父类还是自己,都什么都没做,所以此处先忽略
		initPropertySources();

		// Validate that all properties marked as required are resolvable
		// see ConfigurablePropertyResolver#setRequiredProperties
		//这里有两步,getEnvironment(),然后是是验证是否系统环境中有RequiredProperties参数值 如下详情
		// 然后管理Environment#validateRequiredProperties 后面在讲到环境的时候再专门讲解吧
		// 这里其实就干了一件事,验证是否存在需要的属性
		getEnvironment().validateRequiredProperties();

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		// 初始化容器,用于装载早期的一些事件
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

AbstractApplicationContext#getEnvironment()

getEnvironment()的顶层接口位于:EnvironmentCapable,有如下实现

注意ConfigurableApplicationContext是接口,所以其实容器的实现只有AbstractApplicationContext

AbstractApplicationContext:上下文
ConfigurableApplicationContext:容器上下文
GenericFilterBean:Spring的过滤器
HttpServletBean:DispatcherServlet

obtainFreshBeanFactory()

概述

重新创建一个bean工厂,并销毁原工厂。主要工作是创建DefaultListableBeanFactory实例,解析配置文件,注册Bean的定义信息。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

refreshBeanFactory()是具体的刷新BeanFactory。即:AbstractRefreshableApplicationContext#refreshBeanFactory

@Override
protected final void refreshBeanFactory() throws BeansException {
    // 判断是否已经存在BeanFactory,存在则销毁所有Beans,并且关闭BeanFactory
    // 避免重复加载BeanFactory
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        // 创建具体的beanFactory,这里创建的是DefaultListableBeanFactory,最重要的beanFactory spring注册及加载bean就靠它
        // createBeanFactory()这个方法,看下面,还有得说的
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
    
        // 这句比较简单,就是把当前旧容器的一些配置值复制给新容器 
        // allowBeanDefinitionOverriding属性是指是否允对一个名字相同但definition不同进行重新注册,默认是true。
        // allowCircularReferences属性是指是否允许Bean之间循环引用,默认是true.
        // 这两个属性值初始值为空:复写此方法即可customizeBeanFactory
        customizeBeanFactory(beanFactory);
        
        // 这个就是最重要的了,加载所有的Bean配置信息,具体如下详细解释
        // 它属于模版方法,由子类去实现加载的方式
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

createBeanFactory()

// 创建的时候就是new了一个工厂:DefaultListableBeanFactory   这个时候工厂里面所有东西都是默认值,很多还没有完成初始化属性的设置呢
protected DefaultListableBeanFactory createBeanFactory() {
    return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

// 给设置父的BeanFactory,若存在的话
public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
    this();
    setParentBeanFactory(parentBeanFactory);
}

// 父类空构造器有这么些语句
public AbstractAutowireCapableBeanFactory() {
    super();
    
    // 这里是重点。忽略自动装配。这里指定的都是接口。什么意思呢?
    // ignoreDependencyInterface的真正意思是在自动装配时忽略指定接口的实现类中,对外的依赖。(这里面注意:@Autowired和它的关系,其实是有坑的,后续会专门讲解这个坑)
    ignoreDependencyInterface(BeanNameAware.class);
    ignoreDependencyInterface(BeanFactoryAware.class);
    ignoreDependencyInterface(BeanClassLoaderAware.class);
}

//找到父的,若存在就返回 若存在父容器就存在父的BeanFactory
@Nullable
protected BeanFactory getInternalParentBeanFactory() {
    return (getParent() instanceof ConfigurableApplicationContext) ?
            ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
}

AnnotationConfigWebApplicationContext#loadBeanDefinitions()方法,加载Bean的定义

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
    // 初始化这个脚手架 其实就是直接new出实例。具体做的工作,下面有相关博文链接
    AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
    ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);

    // 生成Bean的名称的生成器,如果自己没有setBeanNameGenerator(可以自定义),这里目前为null
    BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
    if (beanNameGenerator != null) {
        reader.setBeanNameGenerator(beanNameGenerator);
        scanner.setBeanNameGenerator(beanNameGenerator);
        //若我们注册了beanName生成器,那么就会注册进容器里面
        beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
    }
    
    //这是给reader和scanner注册scope的解析器  此处为null
    ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
    if (scopeMetadataResolver != null) {
        reader.setScopeMetadataResolver(scopeMetadataResolver);
        scanner.setScopeMetadataResolver(scopeMetadataResolver);
    }

    // 此处注意了:annotatedClasses和basePackages一般是选其一(当然看到此处,他们是可以并存的)
    //我们可以自己指定annotatedClasses 配置文件,同时也可以交给下面扫描
    if (!this.annotatedClasses.isEmpty()) {
        
        // 这里会把所有的配置文件输出=======info日志  请注意观察控制台
        if (logger.isInfoEnabled()) {
            logger.info("Registering annotated classes: [" +
                    StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
        }
        
        // 若是指明的Bean,就交给reader去处理,至于怎么处理,见上篇博文的doRegisterBean去怎么解析每一个Config Bean的
        reader.register(ClassUtils.toClassArray(this.annotatedClasses));
    }
    
    // 也可以是包扫描的方式,扫描配置文件的Bean
    if (!this.basePackages.isEmpty()) {
        // 输出对应的info日志
        if (logger.isInfoEnabled()) {
            logger.info("Scanning base packages: [" +
                    StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
        }
        
        // 这里重要了,scan方法具体做了什么事,上篇博文也有详细的介绍,请参阅
        scanner.scan(StringUtils.toStringArray(this.basePackages));
    }
    
    // 此处的意思是,也可以以全类名的形式注册。比如可以调用setConfigLocations设置(这在xml配置中使用较多)  可以是全类名,也可以是包路径
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        for (String configLocation : configLocations) {
            try {
                Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
                reader.register(clazz);
            } catch (ClassNotFoundException ex) {
                // 发现不是全类名,那就当作包扫描吧
                int count = scanner.scan(configLocation);
            }
        }
    }
}

postProcessBeanFactory(beanFactory)

空方法,允许在子类中对beanFactory进行后置处理。

invokeBeanFactoryPostProcessors(beanFactory)

概述

该方法的作用是执行所有的BeanFactoryPostProcessor,由于Spring会内置一个BeanFactoryPostProcessor,即ConfigurationClassPostProcessor(如果开发人员不自定义,默认情况下只有这一个BeanFactoryPostProcessor),这个后置处理器在处理时,会解析出所有交由Spring容器管理的Bean,将它们解析成BeanDefinition,然后放入到BeanFactory的BeanDefinitionMap中。

该方法最终会调用到PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法,主要作用是执行所有BeanFactoryPostProcessor的postProcessorBeanFactory()方法。BeanFactoryPostProcessor又分为两种情况,一种是直接实现BeanFactoryPostProcessor接口的类,另一种情况是实现了BeanDefinitionRegistryPostProcessor接口(BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口)。

在执行过程中先执行所有的BeanDefinitionRegistryPostProcessor的postProcessorBeanDefinitionRegistry()方法,然后再执行BeanFacotryPostProcessor的postProcessorBeanFactory()方法。

默认情况下,Spring有一个内置的BeanFactoryPostProcessor,即:ConfigurationClassPostProcessor类,该类实现了BeanDefinitionRegistryPostProcessor类,所以会执行ConfigurationClassPostProcessor.postProcessorBeanDefinitionRegistry,ConfigurationClassPostProcessor的UML图如上(删减了部分不重要的继承关系)

registerBeanPostProcessors(beanFactory)

另见:Spring–BeanPostProcessor–作用/介绍 – 自学精灵

概述

该方法的作用是找到所有的BeanPostProcessor,然后将这些BeanPostProcessor实例化(会调用getBean()方法,getBean()方法的主要逻辑是,如果bean存在于BeanFactory中,则返回bean;如果不存在,则会去创建。在后面会仔细分析getBean()的执行逻辑)。将这些PostProcessor实例化后,最后放入到BeanFactory的beanPostProcessors属性中。

问题:如何找到所有的BeanPostProcessor? 包括Spring内置的和开发人员自定义的。

由于在refresh()方法中,会先执行完invokeBeanFactoryPostProcessor()方法,这样所有自定义的BeanPostProcessor类均已经被扫描出并解析成BeanDefinition(扫描和解析又是谁做的呢?ConfigurationClassPostProcessor做的),存入至BeanFactory的BeanDefinitionMap,所以这儿能通过方法如下一行代码找出所有的BeanPostProcessor,然后通过getBean()全部实例化,最后再将实例化后的对象加入到BeanFactory的beanPostProcessors属性中,该属性是一个List集合。

最后再重新注册了ApplicationListenerDetector,这样做的目的是为了将ApplicationListenerDetector放入到后置处理器的最末端

registerBeanPostProcessor() 最终调用的是PostProcessorRegistrationDelegate.registerBeanPostProcessors(),下面是PostProcessorRegistrationDelegate.registerBeanPostProcessors()方法的代码。

BeanPostProcessor存在优先级,实现了PriorityOrdered接口的优先级最高,其次是Ordered接口,最后是普通的BeanPostProcessor。优先级最高的,会最先放入到beanPostProcessors这个集合的最前面,这样在执行时,会最先执行优先级最高的后置处理器(因为List集合是有序的)。这样在实际应用中,如果我们碰到需要优先让某个BeanPostProcessor执行,则可以让其实现PriorityOrdered接口或者Ordered接口。

initMessageSource()

用来支持消息国际化,现在一般项目中不会用到国际化相关的知识。

initApplicationEventMulticaster()

概述

该方法初始化了一个事件广播器,如果容器中存在了beanName为applicationEventMulticaster的广播器,则使用该广播器;如果没有,则初始化一个SimpleApplicationEventMulticaster。该事件广播器是用来做应用事件分发的,这个类会持有所有的事件监听器(ApplicationListener),当有ApplicationEvent事件发布时,该事件监听器能根据事件类型,检索到对该事件感兴趣的ApplicationListener。

源码

protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // 判断spring容器中是否已经存在beanName = applicationEventMulticaster的事件广播器
    // 例如:如果开发人员自己注册了一个
    // 如果存在,则使用已经存在的;否则使用spring默认的:SimpleApplicationEventMulticaster
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    }
    else {
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    }
}

onRefresh()

概述

执行其他的初始化操作,例如和SpringMVC整合时,需要初始化一些其他的bean。对于纯Spring工程来说,onRefresh()方法是一个空方法。

如果我们整合了SpringMVC,它会启动一个TomcatServer这个服务器。

源码

 如果我们整合了SpringMVC,则其其最终覆写方法为:ServletWebServerApplicationContext#onRefresh()

protected void onRefresh() {
    super.onRefresh();

    try {
        this.createWebServer();
    } catch (Throwable var2) {
        throw new ApplicationContextException("Unable to start web server", var2);
    }
}
private void createWebServer() {
    WebServer webServer = this.webServer;
    ServletContext servletContext = this.getServletContext();
    if (webServer == null && servletContext == null) {
        ServletWebServerFactory factory = this.getWebServerFactory();
        this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
        this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
        this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
    } else if (servletContext != null) {
        try {
            this.getSelfInitializer().onStartup(servletContext);
        } catch (ServletException var4) {
            throw new ApplicationContextException("Cannot initialize servlet context", var4);
        }
    }

    this.initPropertySources();
}

registerListeners()

概述

将自定义的listener的bean名称放入到事件广播器中,同时还会将早期的ApplicationEvent发布(对于单独的Spring工程来说,在此时不会有任何ApplicationEvent发布,但是和SpringMVC整合时,SpringMVC会执行onRefresh()方法,在这里会发布事件)。

源码

protected void registerListeners() {
    // Register statically specified listeners first.
    for (ApplicationListener<?> listener : getApplicationListeners()) {
  getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // 从BeanFactory中找到所有ApplicationListener,但不初始化,因为要在后面bean实例化的过程中,让所有的BeanPostProcessor去改造它们
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        // 将事件监听器的beanName放入到事件广播器中
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // 发布早期的事件(纯的spring工程,在此时一个事件都没有)
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

finishBeanFactoryInitialization(beanFactory)

概述

该方法十分重要,它完成了所有非懒加载的单例Bean的实例化和初始化,属性的填充以及解决了循环依赖等问题。

详述

见: Spring-Bean的创建过程/获取流程 – 自学精灵

finishRefresh()

概述

  • 清除上下文资源缓存(如扫描中的ASM元数据)
  • 初始化上下文的生命周期处理器,并刷新(找出Lifecycle接口的实现类(bean)并执行其onRefresh()方法。
  • 发布ContextRefreshedEvent事件告知对应的ApplicationListener进行相应操作

代码

protected void finishRefresh() {
    this.clearResourceCaches();
    this.initLifecycleProcessor();
    this.getLifecycleProcessor().onRefresh();
    this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
    LiveBeansView.registerApplicationContext(this);
}

resetCommonCaches()

概述

在前面创建bean时,对单例bean的元数据信息进行了缓存,而单例bean在容器启动后,不会再进行创建了,因此这些缓存的信息已经没有任何用处了,在这里进行清空,释放部分内存。

代码

protected void resetCommonCaches() {
    ReflectionUtils.clearCache();
    AnnotationUtils.clearCache();
    ResolvableType.clearCache();
    CachedIntrospectionResults.clearClassLoader(this.getClassLoader());
}
2

评论7

请先

  1. 1、运行 SpringApplication.run() 方法; 2、确定应用程序类型; 3、加载所有的初始化器(springboot自带初始化器,从从 META-INF/spring.factories 配置文件中加载; spring.factories文件里面,看到开头是 org.springframework.context.ApplicationContextInitializer 接口就是初始化器了.); 4、加载所有的监听器(加载监听器也是从 META-INF/spring.factories 配置文件中加载的,监听器加载的是实现了ApplicationListener接口的类.); 5、设置程序运行的主类(deduceMainApplicationClass(); 这个方法仅仅是找到main方法所在的类,为后面的扫包作准备,deduce是推断的意思,所以准确地说,这个方法作用是推断出主方法所在的类); 6、开启计时器(计算springboot启动花了多长时间;程序运行到这里,就已经进入了run方法的主体了,第一步调用的run方法是静态方法,那个时候还没实例化SpringApplication对象,现在调用的run方法是非静态的,是需要实例化后才可以调用的,进来后首先会开启计时器); // 实例化计时器 StopWatch stopWatch = new StopWatch(); // 开始计时 stopWatch.start(); 7、将java.awt.headless设置为true(表示运行在服务器端,在没有显示器?和鼠标键盘的模式下照样可以工作,模拟输入输出设备功能;即使没有检测到显示器,也允许其启动.对于服务器来说,是不需要显示器的,所以要这样设置.); 8、获取并启用监听器(通过监听器来实现初始化的的基本操作做了2件事情: 1、创建所有Spring运行监听器并发布应用启动事件;2、启用监听器;); 9、设置应用程序参数(将执行run方法时传入的参数封装成一个对象;这个参数是从哪来的呢?其实就是main方法里面执行静态run方法传入的参数。); 10、准备环境变量(准备环境变量,包含系统属性和用户配置的属性,执行的代码块在 prepareEnvironment 方法内。); 11、忽略bean信息(这个方法configureIgnoreBeanInfo() 这个方法是将 spring.beaninfo.ignore 的默认值设为true,意思是跳过beanInfo的搜索,其设置默认值的原理和第7步一样); 12、打印banner信息(他在哪里打印的呢?他在SpringBootBanner.java里面打印的,这个类实现了Banner接口;banner信息是直接在代码里面写死的;如果想要改成自定义banner信息,该怎么办呢?只需要在resources目录下添加一个 banner.txt 的文件即可); 13、创建应用程序的上下文(实例化应用程序的上下文, 调用 createApplicationContext() 方法,这里就是用反射创建对象); 14、实例化异常报告器(异常报告器是用来捕捉全局异常使用的,当springboot应用程序在发生异常时,异常报告器会将其捕捉并做相应处理,在spring.factories 文件里配置了默认的异常报告器。需要注意的是,这个异常报告器只会捕获启动过程抛出的异常,如果是在启动完成后,在用户请求时报错,异常报告器不会捕获请求中出现的异常。); 15、准备上下文环境; 15.1、实例化单例的beanName生成器 在 postProcessApplicationContext(context); 方法里面。使用单例模式创建 了BeanNameGenerator 对象,其实就是beanName生成器,用来生成bean对象的名称; 15.2、执行初始化方法 初始化方法有哪些呢?还记得第3步里面加载的初始化器嘛?其实是执行第3步加载出来的所有初始化器,实现了ApplicationContextInitializer 接口的类; 15.3、将启动参数注册到容器中 这里将启动参数以单例的模式注册到容器中,是为了以后方便拿来使用,参数的beanName 为 :springApplicationArguments; 16、刷新上下文(刷新上下文已经是spring的范畴了,自动装配和启动 tomcat就是在这个方法里面完成的); 17、刷新上下文后置处理(afterRefresh方法是启动后的一些处理,留给用户扩展使用,目前这个方法里面是空的。); 18、结束计时器(springboot其实就已经完成了,计时器会打印启动springboot的时长。);
    summerzZ 2024-07-29 0
  2. 有点深。。看了半天自己都不知道自己在看啥
    150003 2024-05-09 2
    • Spring的原理,需要很多Spring实战、知识点才能看懂。第一次看的话大致了解就行。
      自学精灵 2024-05-09 1
    • 面试的时候,把这个上面的全都回来上来,
      ゞ╃尐沐則颩...o 2024-08-26 1
      • 回答出主体逻辑就可以
        自学精灵 2024-08-27 2
  3. bannner,拼错
    竹杖,山水间 2024-01-03 0
    • 好的 已修复
      自学精灵 2024-01-03 0
显示验证码
没有账号?注册  忘记密码?

社交账号快速登录