2. Spring Boot项目启动原理初探

SpringBoot从宏观上说,就是对spring容器进行了一层包装。它内部的入口是利用 SpringApplication类的static的 run 方法进行启动的,调用的图:

  

上图中的这些方法都位于org.springframework.boot.SpringApplication这个类中,由此可见SpringApplication这个类在springboot框架中的作用。

//调用示例:

public static void main(String[] args) throws Exception {
  SpringApplication.run(Examples.class, args);
}

SpringApplication类提供了两个static的run方法:

public static ConfigurableApplicationContext run(Object source, String... args) {
        return run(new Object[] { source }, args);
}


public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
        return new SpringApplication(sources).run(args);
}

上面两个方法其实就是一个,最终都会创建一个SringApplication实例,在构造时会处理传入的 sources 参数,而且这souces类可以是多个,调用的方式还可以这样:

public static void main(String[] args) throws Exception {

        Class<?>[] primarySources = new Class<?>[] { Examples.class , Examples1.class } ;
  SpringApplication.run( primarySources , args);
}

SpringApplication构造方法如下:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  this.resourceLoader = resourceLoader;
  Assert.notNull(primarySources, "PrimarySources must not be null");
  this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  this.webApplicationType = WebApplicationType.deduceFromClasspath();

  //用来查找每个jar和类路径下的/META-INF/spring.factories文件,并获取其中的特定接口的配置的
  setInitializers((Collection) getSpringFactoriesInstances( 
  ApplicationContextInitializer.class)); //找出每个jar和类路径下的/META-INF/spring.factories文件中配置的ApplicationContextInitializer类
  setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

  this.mainApplicationClass = deduceMainApplicationClass(); //推断出带有main方法的运行类 
}

上面的代码通过构造完成初始化之后,紧接着就是调用SpringApplication类的实例 run方法,代码如下:

public ConfigurableApplicationContext run(String... args) {
    //StopWatch作用是用来统计spring实例运行时间
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        
        //ConfigurableApplicationContext接口提供了对Spring容器的配置功能
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            // 1. 会执行ApplicationContextInitializer接口进行初始化工作
            // 2. 对外发布监听事件
            // 3. 优先创建有特定作用的单例bean
            // 4. 把带有main方法的主类作为bean的配置源,并从配置源中加载bean信息到容器中
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            //spring容器的生命周期处理,该方法完成后单例bean实例就创建了
            refreshContext(context);
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            //对外发布监听事件
            listeners.started(context);
            //我们在开发中可能会有这样的情景。需要在容器启动的时候执行一些内容。比如读取配置文件,数据库连接之类的。SpringBoot给我们提供了两个接口来帮助我们实现这种需求。这两个接口分别为CommandLineRunner和ApplicationRunner。他们的执行时机为容器启动完成的时候。
            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;
    }

至此,SpringApplication的实例run方法执行完成,该方法主要是完成spring容器的创建和启动

原文地址:https://www.cnblogs.com/hzhuxin/p/7737945.html