美文网首页
从入口看springboot

从入口看springboot

作者: August_01 | 来源:发表于2020-04-08 20:52 被阅读0次

    前言

    看很多springboot相关书籍,都是先讲框架,讲设计模式,讲模块,讲扩展功能,但是往往只能给读者形成一个大概的印象或者作为一本工具来用,或者作为一本面试准备书籍。所谓一知半解大概就是现在我的状态,能熟练使用,也能说出一些原理,但是没有串联起来,没法全局看问题,站在巨人的肩膀只能看到巨人的脚。

    回想我工作中处理各种问题,也是从入口处,一步一步往下走,因此也准备从springboot启动main方法一步一步往下走,看springboot具体经历了什么 ,载入提炼整个springboot的框架结构。

    最简单的springboot启动类

    /**
     * springboot原理学习项目
     */
    @SpringBootApplication
    public class SpringLeanApplication {
        public static void main(String[] args) {
            /// springboot是提供启动入口
            SpringApplication.run(SpringLeanApplication.class, args);
        }
    }
    

    类SpringApplication备注

     * <ul>
     * <li>Create an appropriate {@link ApplicationContext} instance (depending on your
     * classpath)</li>
     * <li>Register a {@link CommandLinePropertySource} to expose command line arguments as
     * Spring properties</li>
     * <li>Refresh the application context, loading all singleton beans</li>
     * <li>Trigger any {@link CommandLineRunner} beans</li>
     * </ul>
    
    1.  创建ApplicationContext实例
    3.  刷新上下文,加载所有的单例bean对象
    2.4暂时忽略 
    
    写备注很重要,写来是看的,别只看代码,也要看备注啊
    

    顺便说一句,作者很多,合作很重要

     * @author Phillip Webb
     * @author Dave Syer
     * @author Andy Wilkinson
     * @author Christian Dupuis
     * @author Stephane Nicoll
     * @author Jeremy Rickard
     * @author Craig Burke
     * @author Michael Simons
     * @author Madhura Bhave
     * @author Brian Clozel
     * @author Ethan Rubinson
     * @since 1.0.0
    

    第一章 启动调用关系

    // 方法1
     public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class<?>[] { primarySource }, args);
    }
    // 方法2
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return new SpringApplication(primarySources).run(args); // run执行启动
    }
    // 方法3
    public SpringApplication(Class<?>... primarySources) {
        this(null, primarySources);
    }
    // 方法4
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
            // 1)web启动类型 react/servlet/非web启动
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
           // 2)设置初始化类
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
           // 3)设置监听
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }
    

    SpringApplication做了3件事情

    1. 设置web启动类型
    2. 加载initializer
    0 = "org.springframework.boot.devtools.restart.RestartScopeInitializer"
    1 = "org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer"
    2 = "org.springframework.boot.context.ContextIdApplicationContextInitializer"
    3 = "org.springframework.boot.context.config.DelegatingApplicationContextInitializer"
    4 = "org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer"
    5 = "org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer"
    6 = "org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
    7 = "org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener"
    
    1. 加载listener
    0 = "org.springframework.boot.devtools.restart.RestartApplicationListener"
    1 = "org.springframework.boot.devtools.logger.DevToolsLogFactory.Listener"
    2 = "org.springframework.boot.ClearCachesApplicationListener"
    3 = "org.springframework.boot.builder.ParentContextCloserApplicationListener"
    4 = "org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor"
    5 = "org.springframework.boot.context.FileEncodingApplicationListener"
    6 = "org.springframework.boot.context.config.AnsiOutputApplicationListener"
    7 = "org.springframework.boot.context.config.ConfigFileApplicationListener"
    8 = "org.springframework.boot.context.config.DelegatingApplicationListener"
    9 = "org.springframework.boot.context.logging.ClasspathLoggingApplicationListener"
    10 = "org.springframework.boot.context.logging.LoggingApplicationListener"
    11 = "org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener"
    12 = "org.springframework.boot.autoconfigure.BackgroundPreinitializer"
    

    第二章 SpringApplication.run()方法说明

    run方法执行最终的启动过程

    /**
        * Run the Spring application, creating and refreshing a new
         * {@link ApplicationContext}.
         * @param args the application arguments (usually passed from a Java main method)
         * @return a running {@link ApplicationContext}
         */
        public ConfigurableApplicationContext run(String... args) {
                    // 秒表 统计多个任务执行时长
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            ConfigurableApplicationContext context = null;
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
                   // 后面有说明,很久以前生成验证码的时候遇到的一个问题记录了下
            configureHeadlessProperty();
                   // 获取runlistener
            SpringApplicationRunListeners listeners = getRunListeners(args);
                   // 推送ApplicationStartingEvent事件
            listeners.starting();
            try {
                            // 获取启动参数
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                            // 方法2
                ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
                // 方法3
                            configureIgnoreBeanInfo(environment);
                           // 打印banner
                Banner printedBanner = printBanner(environment);
                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;
        }
    

    1. headless说明

    截屏2020-04-08 下午9.00.23.png

    2. getRunListeners说明

    创建SpringApplicationRunListeners,包含以下listener

    org.springframework.boot.context.event.EventPublishingRunListener
    

    SpringApplicationRunListener内部包含ApplicationEventMulticaster,用于管理对多个ApplicationListener(参考SpringApplication初始化)推送SpringApplicationEvent事件

    3. SpringApplicationRunListener

    持续更新中。。。

    相关文章

      网友评论

          本文标题:从入口看springboot

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