SpringBoot框架——从SpringBoot看IoC容器初始化流程之方法分析

目录

一、概观Spring Boot

二、Spring Boot应用初始化

2.1 初始化入口

2.2 SpringApplication的run方法

2.3 方法分析

三、容器创建与初始化

3.1 creatApplicationContext()方法

3.2 prepareContext(context, environment, listener, applicationArguments, printedBanner)方法

3.3 refreshContext(context)方法

四、总结

一、概观SpringBoot

随着分布式、微服务和云计算时代的到来,Spring Boot框架的重要性日益突显。Spring官方给出的Spring Boot框架的特性:

  • 可以创建独立的Spring应用
  • 直接内嵌Tomcat, Jetty 或者 Undertow,不再需要开发WAR类型文件
  • 提供各式的"starter"依赖,来简化项目的创建配置
  • 任何时候都尽可能地自动化配置Spring和第三方库
  • 提供犹如健康指标检测和外部配置的生产环境特性
  • 完全没有代码生成和不需要xml配置

从官方给出的特性来看,Spring Boot适合做分布式系统和云上应用的底层框架,内嵌容器不需要再安装配置容器,而且提供了很多已经配置好的第三方框架和应用,并且主张“约定大于配置”,即拿来即用,适合使用java config注解配置,让开发人员更关注与业务代码。所以,在这么多诱惑下,自己便决定研究一下Spring Boot框架的源码,从源码来了解Spring Boot的迷人之处。

二、Spring Boot应用初始化

Spring框架的IoC和AOP是其强大之处,而Spring框架下的应用都会使用这两种技术,所以使用该框架的开发人员都应该去了解ioc和aop技术。而Spring Boot是Spring框架的即用版,因此,从Spring Boot源码中学习IoC容器的创建初始化以及AOP技术应用的思想,是我认为比较便捷的方法。同时,还可以学习到Spring Boot在整合Spring和第三方框架及应用的思想和技巧。接下来,我将从Spring Boot应用的启动入口开始分析,逐步分析启动流程。

2.1 初始化入口

下面是Spring Boot应用最简单的启动代码:

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

从这段代码可以知道,应用的主方法main调用了SpringApplication.run()方法,开启了应用初始化。那么,接下来我们看看它是怎么初始化容器的。

2.2 SpringApplication的run方法

    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

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

2.3 方法分析

  • StopWatch类:计时类,计算SpringBoot应用的启动时间。
  • SpringBootExceptionReporter类:是一个回调接口,用于支持SpringApplication启动错误的自定义报告。
  • configureHeadlessProper()方法:配置Headless模式配置,该模式下系统缺少显示设备、鼠标或键盘,而服务器端往往需要在该模式下工作。
  • getRunListeners(args)方法:获取SpringApplicationRunListeners类,是SpringApplicationRunListener类的集合。
  • SpringApplicationRunListener类:SpringApplication的run方法的监听器。
  • DefaultApplicationArguments(args)类:提供访问运行一个SpringApplication的arguments的访问入口。
  • prepareEnvironment(listeners,applicationArguments)方法:创建和配置Environment,同时在调用AbstractEnvironment构造函数时生成PropertySourcesPropertyResolver类。
  • configureIgnoreBeanInfo(environment)方法:配置系统IgnoreBeanInfo属性。
  • printBanner(environment)方法:打印启动的图形,返回Banner接口实现类。
  • createApplicationContext()方法:根据SpringApplication构造方法生成的webApplicationType变量创建一个ApplicationContext,默认生成AnnotationConfigApplicationContext。
  • getSpringFactoriesInstances(SpringBootExceptionRepoter.class, new Class[] {ConfigurableApplicationContext.class }, context)方法:获取SpringBootExceptionReporter类的集合。
  • prepareContext(context, environment, listener, applicationArguments, printedBanner)方法:设置Environment,在ApplicationContext中应用所有相关的后处理,在刷新之前将所有的ApplicationContextInitializers应用于上下文,设置SpringApplicationRunLIstener接口实现类实现多路广播Spring事件,添加引导特定的单例(SpringApplicationArguments, Banner),创建DefaultListableBeanFactory工厂类,从主类中定位资源并将资源中的bean加载进入ApplicationContext中,向ApplicationContext中添加ApplicationListener接口实现类。
  • refreshContext(context)方法:调用AbstractApplicationContext的refresh()方法初始化DefaultListableBeanFactory工厂类。
  • afterRefresh(CongigurableApplicationContext context, ApplicationArguments args)方法:在刷新ApplicationContext之后调用,在SpringAppliation中是方法体为空的函数,故不做任何操作。
  • listeners.started(context)方法:在ApplicationContext已经刷新及启动后,但CommandLineRunners和ApplicationRunner还没有启动时,调用该方法向容器中发布SpringApplicationEvent类或者子类。
  • callRunners(context, applicationArguments)方法:调用应用中ApplicationRunner和CommanLineRunner的实现类,执行其run方法,调用时机是容器启动完成之后,可以用@Order注解来配置Runner的执行顺序,可以用来读取配置文件或连接数据库等操作。
  • listeners.running(context)方法:在容器刷新以及所有的Runner被调用之后,run方法完成执行之前调用该方法。调用之前得到的SpringApplicationRunListeners类running(context)方法。
  • 最后,向应用中返回一个之前获得到的ApplicationContext。

三、容器创建与初始化

在第二部分的SpringApplication的run()方法中,我们已经大致了解到了Spring Boot应用在启动时做了哪些工作,与容器初始化相关的方法是createApplciationContext()、prepareContext(context, environment, listener, applicationArguments, printedBanner)以及refreshContext(context)。那这一部分将关注与Spring IoC容器的创建和初始化相关的SpringApplication方法。

3.1 creatApplicationContext()方法

根据SpringApplication构造方法生成的webApplicationType变量创建一个ApplicationContext,默认生成AnnotationConfigApplicationContext。

(1)时序图

SpringBoot框架——从SpringBoot看IoC容器初始化流程之方法分析

(2)方法的源码

    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch(this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
                case REACTIVE:
                    contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                    break;
                default:
                    contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                }
            } catch (ClassNotFoundException var3) {
                throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
            }
        }

        return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    }

(3)方法分析

a. 方法根据applicationContextClass变量是否为空,决定是否执行下面的switch语句,而applicationContextClass变量是由SpringApplicationBuilder类中的contextClass()方法调用ApplicationContext的setApplicationContextClass()赋值的,默认为空;

b. webApplicationType变量是SpringApplication.run()方法调用构造方法时赋值的;

c. switch语句通过反射根据webApplicationType生成对应的容器,分别是AnnotationConfigServletWebServerApplicationContext、AnnotationConfigReactiveWebServerApplicationContext以及AnnotationConfigApplicationContext的,默认生成的是AnnotationConfigApplicationContext,同时,其构造函数生成AnnotedBeanDefinitonReader和ClassPathBeanDefinitionScanner类;

d. 最后,通过BeanUtils工具类将获取到的容器类转换成ConfigurableApplicationContext类,返回给应用使用。

3.2 prepareContext(context, environment, listener, applicationArguments, printedBanner)方法

prepareContext方法的作用是,设置Environment,在ApplicationContext中应用相关的后处理,在刷新之前将任何的ApplicationContextInitializers应用于上下文,设置SpringApplicationRunLIstener接口实现类实现多路广播Spring事件,添加引导特定的单例(SpringApplicationArguments, Banner),创建DefaultListableBeanFactory工厂类,从主类中定位资源并将资源中的bean加载进入ApplicationContext中,向ApplicationContext中添加ApplicationListener接口实现类。接下来,我们将从源码入手,逐步分析prepareContext()方法所做的工作。

(1)prepareContext()源码

    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        this.postProcessApplicationContext(context);
        this.applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }

        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        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());
        }

        Set<Object> sources = this.getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        this.load(context, sources.toArray(new Object[0]));
        listeners.contextLoaded(context);
    }

(2)prepareContext时序图

SpringBoot框架——从SpringBoot看IoC容器初始化流程之方法分析

(3)方法解析

  • context.setEnvironemnt(environment)方法:为容器设置环境,该Environment类是run()方法中的prepareEnvironment()方法获取的,默认为StandardEnvironment类。

  • postProcessApplicationContext(context)方法:在ApplicationContext中应用相关的后处理。
    a. 根据应用中的beanNameGernerator引用是否为空(默认为空),决定是否向容器中注入BeanNameGenerator类的实现类;
    b. 根据resourceLoader引用是否为空(默认为DefaultResourceLoader类,在printBanner()阶段获得)以及context的类型,决定配置resource的地方和方式,若context(默认为AnnotationConfigApplicationContext)为GenericApplicationContext类或子类,则向context中添加    resourceLoader,若context为DefaultResourceLoader类或子类,则向context中添加resourceLoader类的ClassLoader类实例;
    c. 根据addConversionService的布尔值(默认为true),决定是否向容器中添加ApplicationConversionServivce类实例。

  • applyInitializers(context)方法:在容器刷新之前,应用所有的ApplicationContextInitializer接口实现类。遍历执行getInitializers()方法得到的集合的initialize(context)方法初始化context容器,而for方法遍历的ApplicationContextInitializer集合是应用执行SpringApplication构造函数时getSpringFactoriesInstances()方法设置的。

  • listeners.contextPrepared(context)方法:遍历执行run方法里getRunListeners()得到的SpringApplicationRunListeners (SpringApplicationRunListener的集合)的contextPrepared(context)方法。执行时机是,ApplicationContext容器完成创建和准备之后,并且只调用一次。容器提供的SpringApplicationRunListener接口实现类是EventPublishingRunListener类,该类构造函数生成的SimpleApplciationEventMulticaster类用来多路广播发布SpringApplicationEvent接口的实现类。

  • logStartupInfo(context.getParent()==null)方法:记录启动信息,其子类可以覆盖该方法以添加附加信息。

  • logStartupProfileInfo(context)方法:记录活动配置文件信息。

  • context.getBeanFactory()方法:调用之前得到的ApplicationContext容器(默认AnnotationConfigApplicationContext)的getBeanFactory()得到一个BeanFactory接口实现类(默认DefaultListableBeanFactory类),转换为ConfigurableListableBeanFactory类。

  • beanFactory.registerSingleton("springApplicationArguments", applicationArguments)方法:往容器中注册ApplicationArguments接口实现类(默认DefaultApplicationArguments类)的单例。

  • beanFactory.registerSingleton("springBootBanner", printedBanner)方法:向容器中添加printBanner(environment)方法返回的Banner类的单例。

  • ((DefaultListableBeanFactory) beanfactory).setAllowBeanDefinitionOverring(this.allowBeanDefinitionOverriding)方法:设置BeanDefinitio覆盖的开关。

  • getAllSources()方法:获取到应用中所有的资源,即Bean的资源定位阶段。该资源获取的地点是,在SpringApplication构造方法中产生,将run(MyApplication.class,args)中的MyApplication.class转换存储到LinkedHashSet<>中,并返回一个该资源Set的引用primarySources,在getAllSource()方法中获取该primarySources。

  • Assert.notEmpty(sources, "Sources must not be empty")方法:断言,判断获取到的sources是否为空,为空则停止应用并返回错误信息。

  • load(context, sources.toArray(new Object[0]))方法:从上面获取的资源中加载bean进入ApplicationContext中,即bean的加载阶段。加载流程如下:
    a.创建了BeanDefinitionLoader类,将传入的context容器类型转换为BeanDefinitionRegistry(该转换局部生效);
    b.创建了AnnotedBeanDefinitionReader类、AnnotationScopeMetadataResolver类、AnnotationBeanNameGenerator类以及ConditionEvaluator类;
    c.创建XmlBeanDefinitionReader类、SimpleSaxErrorHandler类、XmlValidationModeDetector类以及NameThreadLocal类;
    d. 创建了ClassPathBeanDefintionScannerl类以及GroovyBeanDefintionReader类(该类根据BeanDefinitionLoader中的isGroovyPresent()返回的布尔值决定是否创建);
    e. 配置得到的BeanDefinitionLoader,并调用其load()方法,开始加载BeanDefinition;
    f. 根据传入的资源的类型,决定加载Bean的方式以及BeanDefinition的类型(默认为AnnotatedGenericBeanDefinition类);
    g. 解析含有@Scope注解的BeanDefinition获得其ScopeMetadata,并将scope添加到获得的BeanDefinition中;
    h. 解析BeanDefinition获得beanName;
    i. 解析含有@Lazy注解的BeanDefinition,根据注解属性值决定是否执行setLazyInit()方法;
    j. 遍历函数输入参数BeanDefinitionCustomizer(该接口是功能性接口)的集合,执行其customizer(abd)方法;
    k. 将刚才得到的BeanDefinition和beanName添加到BeanDefinitionHolder中;
    i. 利用AOP框架创建作用域代理类,根据刚刚获得的ScopeMetadata的getScopedProxyMode()方法返回的值,ScopedProxyMode 决定是否生成代理类并决定使用jdk代理生成代理类还是cglib生成代理类,并将得到的proxyDefinition代替之前的BeanDefinition添加到BeanDefinitionHolder中;
    m. 向容器中注册别名aliases和beanName;

  • listeners.contextLoaded(context)方法:遍历执行之前获得的SpringApplicationRunListener接口实现类的contextLoaded(context)方法。

3.3 refreshContext(context)方法

调用AbstractApplicationContext的refresh()方法初始化DefaultListableBeanFactory工厂类。

(1)refreshContext(context)源码

    private void refreshContext(ConfigurableApplicationContext context) {
        this.refresh((ApplicationContext)context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
            }
        }

    }

调用的AbstractApplicationContext.refresh()源码:

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

(2)refreshContext(context)时序图

下面时refreshContext(context)实际刷新容器的AbstractApplicationContext.refresh()的时序图:

SpringBoot框架——从SpringBoot看IoC容器初始化流程之方法分析

(3)方法分析

  • prepareRefresh()方法:为刷新准备好容器。
    a. 设置启动时间;
    b. 设置标示当前context是否活动的标签,active为true,closed为false,类型为AtomicBoolean;
    c. 在context环境中初始化placeholder属性源,默认不做任何事情;
    d. 验证所有标记required的property都是可解析的;
    e. 创建ApplicationEvent的集合,即LinkedHashSet<ApplicationEvent>。一旦多路广播器可用(即prepareContext()阶段得到的SimpleApplicationEventMulticaster类),便允许发布早期的ApplicationEnvent的集合;

  • obtainFreshBeanFactory()方法:告诉子类刷新内部的bean工厂
    a. 持有一个工厂类单例(默认为DefaultListableBeanFactory),并依靠调用者通过工厂类单例或构造方法注册bean;
    b. 将在AbstarctApplicationContext类生成的id和在DefaultListableBeanFatory生成指向自身的弱引用,存储进入一个由DefaultListableBeanFactory持有的Map中。

  • prepareBeanFactory(beanFactory)方法:准备在context中要使用的beanFactory。配置工厂的标准context特性,比如容器的ClassLoader和后处理器。
    a. 设置ClassLoader;
    b. 设置BeanExpressionResolver接口实现类(为StandardBeanExpressionResolver类);
    c. 设置PropertyEditorRegistrar接口实现类(为ResourceEditorRegistrar类);
    e. 将ApplicationContextAwareProcessort添加进入应用获得的工厂类实例持有的CopyOnWriteArrayList的一个引用中;
    f. 将EnvironmentAware.class、EmbeddedValueResolverAware.class、ResourceLoaderAware.class、ApplicationEventPublisherAware.class、MessageSourceAware.class、MessageSourceAware.class 添加进入应用获得的工厂类实例持有的HashSet的一个引用中;
    g. 在普通工厂类中未注册成为可解析类型的工厂类接口,而MessageSource作为bean被注册(查找到并自动装配)。
    h. 将BeanFactory.class、ResourceLoader.class、ApplicationEventPublisher.class、ApplicationContext.class 添加进入应用获得的工厂类实例持有的ConcurrentHashMap<Class<?>, Object>的一引用中;
    i. 注册为了检测内部bean的早期后处理器,例如ApplicationListeners;
    j. 将ApplicationListenerDetector的实例、LoadTimeWeaverAwareProcessor的实例添加进入应用获得的工厂类实例持有的CopyOnWriteArrayList<BeanPostProcessor>的一个引用中;
    k. 为持有的工厂类设置临时可以匹配类型的ClassLoader,为ContextTypeMatchClassLoader类;
    l. 配置默认的环境单例bean;

  • postProcessBeanFactory(beanFactory)方法:允许容器子类中的bean工厂执行后处理。该方法执行时机时,在ApplicationContext内部bean工厂类标准初始化之后修改它,这时所有的BeanDifinition已经被加载,但是还没有被实例化。继承这个方法允许某些AbstractApplicationContext类的子类中注册特殊的类似BeanPostProcessors的类。默认不做任何操作。

  • invokeBeanFactoryPostProcessors(beanFactory)方法:实例化所有已经注册的BeanFactoryPostProcessor的bean(实例化为单例),并遵循已给出的明确order值调用它,bean实例化与依赖注入开始阶段。
    a. 实际调用了PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessor(beanfactory, getBeanFactoryPostProcessor)方法,在这个方法里完成了实例化和调用任务;
    c. 不实例化FactoryBean,并保留所有常规bean,不初始化它们,让之后的bean工厂后处理器应用他们;
    d. 区分开实现了PriorityOrdered类的BeanDefinitionRegistryPostProcessor类,将其实例化并装入一个ArrayList的容器中;
    e. 将刚刚获得的BeanDefinitionRegistryPostProcessor的集合根据order的值排序;
    f. 遍历调用得到的BeanDefinitionRegistryPostProcessor类bean的postProcessBeanDefinitionBeanDefinitionRegistry(registry)方法;
    g. 清除BeanDefinitionRegistryPostProcessor的ArrayList集合里的bean;
    h. 区分开实现了Ordered类的BeanDefinitionRegistryPostProcessor类,将其实例化并装入一个ArrayList的容器中,并重复执行一次e到g的步骤;
    i. 最后,调用所有其他的BeanDefinitionRegistryPostProcessor,直到不再出现其他的BeanDefinitionRegistryPostProcessor,也重复执行一次e到g的步骤;
    j. 调用到目前为止的已处理的所有处理器的postProcessBeanFactory回调;
    g. 调用context实例注册的factory的processor;
    i. 清空缓存的合并的Bean定义,因为后处理器可能会修改原始的元数据,例如,替换值中的占位符。

  • registerBeanPostProcessors(beanFactory)方法:注册拦截bean创建的bean处理器。
    a. 向context持有的bean factory注册BeanPostProcessorChecker,该检查器其用来记录在BeanPostProcessor实例化期间创建bean时的info信息,即当所有BeanPostProcessor都不对bean进行后处理操作时记录。
    b. 将所有的BeanPostProcessor按照实现PriorityOrdered、Oedered和剩下的区别,分别添加进三个ArrayList容器;
    c. 对刚刚获得ArrayList分别根据order值进行排序,最后整合后注册进入bean factory中;
    d. 重新注册后处理器,用于检测像ApplicationListener的内部类,将其移动到后处理器链的末端,用于提取代理等作用;

  • initMessageSource()方法:为context初始化message源。从容器中获得MessageSource的bean,若没有定义,则会调用父类的MessageSource(无值,并会打印出没有message source的日志信息)。此例为单例。

  • initApplicationEventMulticaster()方法:实例化应用事件多路广播器ApplicationEventMulticaster。从容器中获取ApplicationEventMulticaster的bean,若没有注册,则注入SimpleApplicationEventMulticaster类的bean。

  • onRefresh()方法:该方法使模板方法,在特定的context子类中初始化其他特殊的bean。
    a. 在GenericWebApplicationContext、StaticWebApplicationContext中,该方法初始化了context的ThemeSource;
    b. 在ServletWebServerApplicationContext、ReactiveWebServerApplicationContext中,该方法初始化类context的TnemeSource并创建了一个ServerManager。

  • registerListeners()方法: 检测监听器并注册它们。向刚才获得的ApplicationEventMulticaster中注册实现了ApplicationListener的监听器bean,但不影响那一些可以不用生成bean就可以加载的监听器。

  • finishBeanFactoryInitialization(beanFactory)方法:实例化所有剩下的单例bean(没有执行lazy初始化)。
    a. 初始化context的类型转换服务;
    b. 如果之前没有任何注册的bean后处理器(比如,一个PropertyPlaceholderConfigurer的bean),则注册一个默认的内嵌的值解析器,在这一观点下,优先解析注解属性值;
    c. 尽早初始化LoadTimeWeaverAwarebean,以便尽早注册它们的转换器;
    d. 停止使用临时的类型匹配类加载器;
    e. 允许缓存所有的bean定义元数据,不需要进一步修改了;
    f. 实例化所有剩下的单例(没有Lazy初始化的bean);

  • finishRefresh()方法:发布相应的事件。
    a. 清除context级别的资源缓存(例如,扫描得来的ASM元数据);
    b. 为context初始化生命周期处理器;
    c. 首先向生命周期处理器传播刷新;
    d. 发布最后的事件(ContextRreshedEvent);
    e. 若激活的话,便参与LiveBeansView类的mbean,。

  • destroyBeans()方法:摧毁已经创建的bean,避免悬空资源。

  • cancelRefresh(ex)方法:取消刷新,设置active变量为false。

  • resetCommonCaches()方法:重置Spring中的内省缓存,因为应用可能不再需要单例bean的元数据了。
    a. 清除声明方法缓存,清除声明变量缓存(ConcurrentReferenceHashMap数据类型);
    b. 清除注解相关缓存;
    c. 清除可解析类型相关缓存;
    d. 清除相关类加载器缓存(ConcurrentHashMap)。

四、总结

到此为止,分析了Spring Boot应用启动过程run方法中,自己比较感兴趣的三个方法,再以此延伸又接触到了更多的相关类和相关方法,重新复习了许多java知识(继承、重载、重写、接口、反射以及设计模式)。虽然自己还没有能力写出这么优美的框架,但是从分析源码中自己学习到了不少的框架设计知识,接触到比较底层的设计思想。不尽人意的是,有些方法和重要类的分析由于自己能力有限,解释得还有些模糊,决定在接下来的文章里将这些遗憾弥补回来。欢迎指正!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343