欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

springboot的启动源码流程(菜鸟笔记)

程序员文章站 2024-03-26 13:51:05
...

springboot的启动源码流程

1.几个重要的事件回调机制

//放在类路劲下的META-INF/spring.factories文件中
ApplicationContextInitializer
ApplicationListener

//先执行ApplicationRunner,再执行CommandLineRunner
ApplicationRunner
CommandLineRunner

2.springboot.run(Main.class)分为两部分

//首先spring容器的创建
//执行容器的run方法
new SpringApplication(primarySources).run(args);

3.spring容器的创建

	
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    //保存主配置类
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //判断是否是web应用
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    
    //从类路劲下找到\META-INF\spring.factories配置所有的ApplicationContextInitializer然后保存起来
    //getSpringFactoriesInstances
    //1.从META-INF/spring.factories文件中找实现了ApplicationContextInitializer接口的所有类
    	//1.1 实现类如下
        org.springframework.context.ApplicationContextInitializer=\
        org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
        org.springframework.boot.context.ContextIdApplicationContextInitializer,\
        org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
        org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
    //2.createSpringFactoriesInstances 获取到的全类名,通过反射创建实例
	//3.保存ApplicationContextInitializer创建的实例
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    
    
    //从类路劲下找到\META-INF\spring.factories配置所有实现了ApplicationListener接口的类
    //getSpringFactoriesInstances
    //1.从META-INF/spring.factories文件中找实现了ApplicationListener接口的所有类
    //1.1 实现类如下:
    	org.springframework.context.ApplicationListener=\
        org.springframework.boot.ClearCachesApplicationListener,\
        org.springframework.boot.builder.ParentContextCloserApplicationListener,\
        org.springframework.boot.context.FileEncodingApplicationListener,\
        org.springframework.boot.context.config.AnsiOutputApplicationListener,\
        org.springframework.boot.context.config.ConfigFileApplicationListener,\
        org.springframework.boot.context.config.DelegatingApplicationListener,\
        org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
        org.springframework.boot.context.logging.LoggingApplicationListener,\
        org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
    //2.createSpringFactoriesInstances 获取到的全类名,通过反射创建实例
	//3.保存ApplicationListener创建的实例
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //从配置类中找到有main方法的主类
    this.mainApplicationClass = deduceMainApplicationClass();
}

springboot的启动源码流程(菜鸟笔记)

springboot的启动源码流程(菜鸟笔记)

4.执行容器的run方法

/**
* Run the Spring application, creating and refreshing a new ApplicationContext
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
    //用来打印,方法执行的时间,
    //如:Started BootMasterApplication in 56.783 seconds (JVM running for 69.93)
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    //1.申明ioc容器
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    //2.配置环境变量  java.awt.headless='true'
    configureHeadlessProperty();
    
    //3.在\META-INF\spring.factories中找实现类接口SpringApplicationRunListener的所有类,并依次创建类的实例
    SpringApplicationRunListeners listeners = getRunListeners(args);
    //4.回调SpringApplicationRunListener.starting();依次开启所有的监听器
    listeners.starting();
    try {
        //5.包装传入参数  在Idea工具中添加命令行参数,如username=zzhua password=1234
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        
        //6.准备环境变量
        //6.1 获取或者创建环境,配置环境
        //6.2 回调SpringApplicationRunListener.environmentPrepared(environment);表示环境准备完成
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        //6.3 配置ignore 的Bean信息
        configureIgnoreBeanInfo(environment);
        //7.打印Banner
        Banner printedBanner = printBanner(environment);
        //8.创建ApplicationContext,决定创建web容器还是普通的ioc,反射技术
        context = createApplicationContext();
        //9.异常信息处理
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                                                         new Class[] { ConfigurableApplicationContext.class }, context);
        //10.准备上下文环境
        //10.1 将environment保存到ioc容器中
        //10.2 applyInitializers(),回调前面保存的所有的ApplicationContextInitializer实现类的initialize()方法
        //10.3 回调所有的SpringApplicationRunListener.contextPrepared()
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        //11. spring容器的刷新 applicationContext).refresh(); 【如果是web应用还会创建嵌入式的Tomcat】。 其他章节已经整理
        refreshContext(context);
        
        //空方法,让子类实现
        afterRefresh(context, applicationArguments);
        //12.监控结束,并打印花费时间日志
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }
        //13.所有的SpringApplicationRunListener回调started()方法,表示容器开启完成
        listeners.started(context);
        //14
        //14.1 在ioc容器中获取所有实现了ApplicationRunner和CommandLineRunner接口的类
        //14.2 先回调所有的ApplicationRunner.run()
        //14.3 再回调所有的CommandLineRunner.run()
        callRunners(context, applicationArguments);
    }catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {
        //回调SpringApplicationRunListener.running()
        listeners.running(context);
    }catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    //返回创建好的容器
    return context;
}