Spring-Boot源码分析(一)

概述

随着微服务的兴起,Spring-Boot的被越来越多的公司喜爱。然后出去面试时候,总会被面试官问起,看过Spring-Boot源码吗,接下来就分析下Spring-Boot源码。

源码分析

首先是启动类:

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
              //为入口
        SpringApplication.run(DemoApplication.class, args);
    }
}

在调用之前自定义该实例:

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
            //  判断工程的类型(REACTIVE、NONE、SERVLET)
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
            //获取ApplicationContextInitializer,也是在这里开始首次加载spring.factories文件
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
          //获取监听器,这里是第二次加载spring.factories文件
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

deduceFromClasspath()方法

static WebApplicationType deduceFromClasspath() {
        if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
            return WebApplicationType.REACTIVE;
        }
        for (String className : SERVLET_INDICATOR_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return WebApplicationType.NONE;
            }
        }
        return WebApplicationType.SERVLET;
    }

ApplicationContextInitializer是spring组件spring-context组件中的一个接口,主要是spring ioc容器刷新之前的一个回调接口,用于处于自定义逻辑。
基于SPI扩展,去加载spring.factories文件中的实现类:

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
image.png
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
image.png
//拿到工厂实例
private  Collection getSpringFactoriesInstances(Class type,
            Class[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        Set names = new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }
image.png

接下来看一下run方法:

public ConfigurableApplicationContext run(String... args) {
               
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
                  //第一步:获取并启动监听器
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
                          //第二步:构造容器环境
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
                        //设置需要忽略的bean
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
                         //第三步:创建容器
            context = createApplicationContext();
                        //第四步:实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
            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, 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;
    }

第一步:获取并启动监听器
第二步:构造容器环境
第三步:创建容器
第四步:实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
第五步:准备容器
第六步:刷新容器
第七步:刷新容器后的扩展接口

主要以上七步。
未完待续


你可能感兴趣的:(Spring-Boot源码分析(一))