美文网首页
springboot启动(2) -- 启动流程

springboot启动(2) -- 启动流程

作者: matthewfly | 来源:发表于2021-02-26 11:37 被阅读0次

根据springboot启动(1)的分析,springboot真正启动从应用主类main方法开始,其run方法中由SpringApplication完成真正启动。

  1. new SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = Collections.emptySet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }
  • 配置是否为web应用的lambda方法(默认web应用)
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
  • 创建应用上下文工厂,用于自动装配等(默认SERVLET,及支持注解的servlet)
@FunctionalInterface
public interface ApplicationContextFactory {
    ApplicationContextFactory DEFAULT = (webApplicationType) -> {
        try {
            switch(webApplicationType) {
            case SERVLET:
                return new AnnotationConfigServletWebServerApplicationContext();
            case REACTIVE:
                return new AnnotationConfigReactiveWebServerApplicationContext();
            default:
                return new AnnotationConfigApplicationContext();
            }
        } catch (Exception var2) {
            throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
        }
    };
  • 读取spring.factories文件获取监听配置并创建监听器
  • 配置应用启动类
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
  1. SpringApplication.run
public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
  • 监听器发布应用开始启动
  • 获取应用配置:ConfigurableEnvironment(包含logger、应用环境、应用参数等)
  • 创建应用上下文:createApplicationContext
    默认AnnotationConfigServletWebServerApplicationContext,读取配置环境、加载监听,构造资源加载器reader、pacakge scanner,构造bean工厂加载器。
  • 启动前准备工作:prepareContext
    通过bean工厂生产所需bean,配置各类资源
  • 刷新上下文:refreshContext
    自动装配springboot配置组件(如mybatis等),创建web server(如tomcat)。
  • 再刷新上下文(空实现留作扩展)
  • 发布启动完成事件
  1. 自动装配
    自动装配在AbstractApplicationContext.refresh中完成的,由invokeBeanFactoryPostProcessors方法执行自动装配链条。
  • 获取bean工厂加载器、资源加载器
  • 资源加载器读取spring.factories配置文件,获取待加载bean及其全路径
  • 通过反射获取待加载bean的class对象和构造方法
  • 实例化所有待加载bean,并加入spring容器

上述3个步骤就是springboot启动大致流程,前期主要完成配置环境读取、加载监听器、构造工厂加载器合和资源加载器。其中核心是在刷新上下文refreshContext,包含了web server的启动和自动装备。

自动装配流程:

  • @EnableAutoConfiguration模块的
    通过自定义@Enable模块驱动测试知道,springboot通过@ImportSelector等注解类,实现bean的实例化和注入。@EnableAutoConfiguration同样的实现原理,其ImportSelector接口方法实现中会扫描项目下的spring.factories,获取待加载类。
  • 读取各jar包下spring.factories文件的配置内容,该文件结构为:接口=接口实现类列表,比如mongodb的jar包下
org.springframework.data.web.config.SpringDataJacksonModules=org.springframework.data.mongodb.config.GeoJsonConfiguration
org.springframework.data.repository.core.support.RepositoryFactorySupport=org.springframework.data.mongodb.repository.support.MongoRepositoryFactory
  • @EnableAutoConfiguration模块获取到类后,通过工厂反射实例化待加载类。

在springboot的各功能模块spring.factories文件中配置了大量默认实现接口。再加上springboot的条件装配,通过配置文件实现配置的功能模块。比如,springboot中包含了mongodb的实现MongoTemplate,只需要在配置文件中添加mongodb的依赖,就能在自动装配接的完成mongodb服务MongoTemplate的加载。

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

springboot这种带有默认实现的配置方式,体现了其“规约大于配置”的思想,用户开箱即用,极大提高了开发效率。

参考:https://www.cnblogs.com/trgl/p/7353782.html

相关文章

网友评论

      本文标题:springboot启动(2) -- 启动流程

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