springboot源码解读

一、源码SpringApplication.class主流程,其中重点在刷新应用上下文refreshContext(context).

            //启动计时器
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            //加载SpringApplicationRunListener监听器并开启
            ConfigurableApplicationContext context = null;
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
            configureHeadlessProperty();
            SpringApplicationRunListeners listeners = getRunListeners(args);
            listeners.starting();
try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //准备应用上下文环境environment,包含服务器信息(SystemProperties)以及应用配置信息.yml、.properties
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            configureIgnoreBeanInfo(environment);
            //控制台打印bannner
            Banner printedBanner = printBanner(environment);
            context = createApplicationContext();
            //获取错误报告器
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            //创建beanFactory工厂,将启动类注册为bean放入IOC容器,同时创建annotatedReader,xmlReader,scanner
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            扫描主类所在包获取包路径,后扫描整个包下被@Component,@Service,@Import等注解修饰的类或方法注入IOC容器
            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, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;

源码启动主流程步骤:

二、源码步骤剖析

  1. 准备应用上下文环境

SpringApplication.class

listeners.environmentPrepared(environment); //主要目的是获取ConfigFileApplicationListener加载配置文件

这里有一个PropertySourceLoader的两个实现类:YamlPropertySourceLoader和PropertiesPropertySourceLoader分别用于加载Yaml配置以及Properties配置文件

注:在加载配置文件时很重要的监听器是ConfigFileApplicationListener,几乎所有的加载前准备工作都在这个类实现,其中具体以加载yaml类举例:OriginTrackedYamlLoader类的load()方法进行解析source进行加载(获取到的配置的值放入propertySources中),如下图展示:

到这里准备应用上下文环境的主要工作便完成。

  1. 创建beanFactory工厂(创建IOC容器并初始化)

prepareContext(context, environment, listeners, applicationArguments, printedBanner);  //创建IOC容器并将主类注册为bean

在创建IOC容器时使用了工厂模式,先创建DefaultListableBeanFactory对象,获取里面的beanDefinitionMap(IOC容器,ConcurrentHashMap类型,保证线程安全)对象,并将启动类注入为bean,具体流程如下:

(1)、获取sources里的主类对象调用load()方法将主类注入beandifinitionMap后放入context.

(2)、load()方法细节详情

在注册bean时采用的是adapter适配器模式

至此beanDefinitionMap(IOC)被创建并将主类注册为bean,准备应用上下文工作大致完成。

注:说明一下几个对象之间的包含关系:->表示包含

context(ApplicationContext)->beanFactory(DefaultListableBeanFactory)->beanDefinitionMap<beanName,beanDefinition>(ConcurrentHashMap)

  1. 刷新应用上下文环境(将bean注入IOC)

刷新应用上下文的入口

refreshContext(context);//刷新应用上下文,将项目中的bean注入IOC。

bean注入时非常重要的方法,从这个方法往下走进行注入bean。

在注入bean的过程中注意ConfigurationClassPostProcessor处理器,通过包扫描获得注解判断是否注入为bean的操作在这个后置处理器里进行。

准备解析文件

开始解析

流程解析:(1)、首先获取ComponentScans.class以及ComponentScan.class里的内容(解析的是@SpringBootApplication(scanBasePackages = {"com.example.portionsecurity","com.example.portionuser"})里的内容,其中@SpringBootApplication注解中的scanBasePackages属性与ComponentScan.class中的basePackages等价,如下)

@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};

而后遍历每一个basePackage获取其中需要注册的bean,具体方法为

Set<BeanDefinition> candidates = findCandidateComponents(basePackage);

之后将bean初始化,返回beanDefinitions

(2)、解决@Import注解

processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

(3)、处理beanMethod(bean中定义了一个bean方法,通常用法为自定义bean设置属性等),如下为具体获取beanMethod的步骤

(4)、其余处理步骤就不再详细赘述(如处理默认的接口实现类,处理父类等)

至此context(应用上下文)刷新完毕,服务中的bean被注入IOC。

以上便是整个springboot源码的主体内容,后面的加载tomcat,dispatcherServlet(前端控制器)在这篇文章中便不在赘述。(后续会持续更新细化的内容,请持续关注。。。)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值