美文网首页
springboot启动原理/运行流程/自动配置原理

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

作者: 凉风拂面秋挽月 | 来源:发表于2019-11-08 09:32 被阅读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

    相关文章

      网友评论

          本文标题:springboot启动原理/运行流程/自动配置原理

          本文链接:https://www.haomeiwen.com/subject/rgksbctx.html