springboot启动原理/运行流程/自动配置原理

2019-11-08  本文已影响0人  凉风拂面秋挽月

关于springboot的启动/运行原理,主要有几个重要的回调机制配置在META-INF/spring.factories

ApplicationContextInitializer
SpringApplicationRunListener  
//只需要放在ioc容器中 ApplicationRunner CommandLineRunner
ApplicationRunner 
CommandLineRunner

我们新建一个叫SpringBootWeb的项目,来调试它。

SpringApplication.run(SpringBootWebApplication.class, args);

打断点进入

public static ConfigurableApplicationContext run(Class<?> primarySource,
            String... args) {
        return run(new Class<?>[] { primarySource }, args);
    }

再次f5

public static ConfigurableApplicationContext run(Class<?>[] primarySources,
            String[] args) {
        return new SpringApplication(primarySources).run(args);
    }

可以看到执行过成分为两步,第一步创建SpringApplication对象,第二步执行run方法
f5

创建SpringApplication对象

public SpringApplication(Class<?>... primarySources) {
        this(null, primarySources);
    }

发现是调用本类的另一个构造方法

@SuppressWarnings({ "unchecked", "rawtypes" })
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
               //保存主配置类,保存到primarySources属性中
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
               //判断当前应用是否是一个web应用(通过是否导入web模块)
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
            //getSpringFactoriesInstances就是将META-INF/spring.factories路径下的所有ApplicationContextInitializer保存起来
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
            //将META-INF/spring.factories路径下的所有ApplicationListener保存起来
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
             //从多个配置类中找到有main方法的主配置类
        this.mainApplicationClass = deduceMainApplicationClass();
    }
META-INF/spring.factories 保存了6个Initializer 保存了10个Listener
private Class<?> deduceMainApplicationClass() {
        try {
            StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
            }
        }
        catch (ClassNotFoundException ex) {
            // Swallow and continue
        }
        return null;
    }

运行run方法

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
//声明一个ioc容器,当前为空
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
//获取SpringApplicationRunListeners;从类路径下META‐INF/spring.factories 
        SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的获取SpringApplicationRunListener.starting()方法
        listeners.starting();
        try {
//封装命令行参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
//准备环境,创建环境完成后回调SpringApplicationRunListener的environmentPrepared方法;表示环境准备完成 。
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            configureIgnoreBeanInfo(environment);
//打印springboot图标
            Banner printedBanner = printBanner(environment);
 //创建ApplicationContext;决定创建web的ioc还是普通的ioc
            context = createApplicationContext();
//如果出现异常,exceptionReporters生成异常报告
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
//准备上下文环境:1.将environment保存到ioc中,context.setEnvironment(environment);
//                             2.执行applyInitializers(context);
//applyInitializers(context):回调之前保存的所有的ApplicationContextInitializer的initialize方法 
// 3.回调所有的SpringApplicationRunListener的contextPrepared();
//prepareContext见下方源码1
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
//prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
//刷新容器;ioc容器初始化,扫描所有的配置类,如@controller,@bean等(源码2)如果是web应用,那么tomcat也在这里启动了
            refreshContext(context);
 //从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调 (源码3)       //ApplicationRunner先回调,CommandLineRunner再回调 
            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);
        }
//整个SpringBoot应用启动完成以后返回启动的ioc容器;
        return context;
    }

1源码:prepareContext

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
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // 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);
    }

源码2,将各种扫描的组件加载到ioc容器中

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                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.
                destroyBeans();

                // Reset 'active' flag.
                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...
                resetCommonCaches();
            }
        }
    }

源码3:从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调

private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList<>();
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        AnnotationAwareOrderComparator.sort(runners);
        for (Object runner : new LinkedHashSet<>(runners)) {
            if (runner instanceof ApplicationRunner) {
                callRunner((ApplicationRunner) runner, args);
            }
            if (runner instanceof CommandLineRunner) {
                callRunner((CommandLineRunner) runner, args);
            }
        }
    }
getRunListeners获取的listener
上一篇下一篇

猜你喜欢

热点阅读