SpringBoot的启动过程

2019-09-26  本文已影响0人  香芋牛奶面包

引言

在我之前写的文章中有详细的分析过Spring的启动过程,如果大家有深入阅读过Spring Framework的核心源码,那么阅读Spring Boot的源码相信会更加轻松。个人觉得其实Spring Boot 特别核心的东西其实比较少,其核心仍然是Spring Framework

启动入口

还是一步到位,直接看源码

public ConfigurableApplicationContext run(String... args) {
    // 统计启动时间
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    // 设置 java.awt.headless 参数
        configureHeadlessProperty();
    // 获取监听器
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            // 创建 context容器
            context = createApplicationContext();
            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;
    }
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);
            }
        }
    // 这里会引入一些BeanFactoryProcess,比如 ConfigurationClassPostProcessor 解析Configuration注解的
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

注: 引入的BeanFactoryProcess 的逻辑在DEFAULT_SERVLET_WEB_CONTEXT_CLASS的构造方法中

// 看下 AnnotationConfigServletWebServerApplicationContext 的构造方法
public AnnotationConfigServletWebServerApplicationContext() {
        // 相当于xml中配置了 <context:annotation-config>
        this.reader = new AnnotatedBeanDefinitionReader(this);
        // 相当于xml中配置了 <context:component-scan>
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

我们在看下 AnnotatedBeanDefinitionReader 的构造方法

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
        this(registry, getOrCreateEnvironment(registry));
    }

    /**
     * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry and using
     * the given {@link Environment}.
     * @param registry the {@code BeanFactory} to load bean definitions into,
     * in the form of a {@code BeanDefinitionRegistry}
     * @param environment the {@code Environment} to use when evaluating bean definition
     * profiles.
     * @since 3.1
     */
    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        Assert.notNull(environment, "Environment must not be null");
        this.registry = registry;
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
        // 在这里 注册了一堆的 BeanFactoryProcess 
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

下面主要prepareContext和refreshContext方法

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

        // Add boot specific singleton beans
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }

        // Load the sources
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        // 这里引入了 启动类
        load(context, sources.toArray(new Object[0]));
        listeners.contextLoaded(context);
    }

注: 这里的主要作用就是引入了启动类,加入到 BeanFactory中

总结

Springboot的核心在于自动配置 快速集成 。一些原本需要在Spring xml文件配置的东西,Spring 只需要一个注解就帮我们都做了。不过前文也都说了,核心还是 Spring Framework。

Spring 系列

上一篇下一篇

猜你喜欢

热点阅读