有两大步:①创建spring应用 ②把spring应用跑起来


一、创建SpringApplication

@SpringBootApplication
public class Boot09HelloTestApplication {

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

step into
使用new class把主程序类传进来,然后调用run方法

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
}

step into run方法
第一步,创建spring应用。第二步把spring应用跑起来

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return (new SpringApplication(primarySources)).run(args);
}

step into 看看创建spring应用的过程是怎么的

public SpringApplication(Class... primarySources) {
//调用本类有参构造器,传入两个参数
        this((ResourceLoader)null, primarySources); 
}

step into this方法
初始化了好多属性

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    //第一个属性,资源加载器resourceLoader 
    this.resourceLoader = resourceLoader;
    //断言你有主配置类,如果没有,则报错
    Assert.notNull(primarySources, "PrimarySources must not be null"); 
    //把主配置类信息保存起来,
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); 
    //决定当前web应用的类型。如何决定的看下面的源码
    this.webApplicationType = WebApplicationType.deduceFromClasspath(); 
    //bootstrappers:初始启动引导器(项目一启动就要干什么)。如何获取的看下面的源码
    this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
    //设置初始化器。只要看到getSpringFactoriesInstances这个方法,都是去META-INF/spring.factories文件中有没有配置某个类类,它的值是什么
    //如果找到了ApplicationContextInitializer,就会放到List<ApplicationContextInitializer<?>> initializers里
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //设置监听器。去spring.factories文件中有没有配置ApplicationListener类,它的值是什么
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //找主程序。决定哪个是主程序。如何决定的看下面的源码分析
    this.mainApplicationClass = deduceMainApplicationClass();
    }

image.png


如何决定当前web应用的类型??Servlet or 响应式编程?

static WebApplicationType deduceFromClasspath() {
    //使用ClassUtils工具类判断当前系统有没有导入org.springframework.web.reactive.DispatcherHandler响应式编程的请求处理器
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
    && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
      //如果是响应式编程,相当于导入了DispatcherHandler类,就会返回它是一个响应式编程
      return WebApplicationType.REACTIVE;
    }
    //如果是原生的serlvet编程
    for (String className : SERVLET_INDICATOR_CLASSES) {
      if (!ClassUtils.isPresent(className, null)) {
          return WebApplicationType.NONE;
      }
    }
    //如果是原生的serlvet编程,就会返回它是一个原生的serlvet编程
    return WebApplicationType.SERVLET;
}

如何获取初始化启动器??

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}

//进入getSpringFactoriesInstances方法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    //获取类的加载器
    ClassLoader classLoader = getClassLoader();
    //spring.factories文件中找类型是org.springframework.boot.Bootstrapper
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //如果没找到,即没人配置它。如果有,就会创建实例并返回
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

如何决定哪个是主程序???

private Class<?> deduceMainApplicationClass() {
    try {
    //去堆栈里找哪个类是有main方法的,有main方法的就是主程序,主程序有很多,只有找到第一个有main方法的就行了
        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;
}

创建SpringApplication小总结

保存一些信息。
判定当前应用的类型。Servlet or 响应式编程
bootstrappers:初始启动引导器(List<Bootstrapper>):去spring.factories文件中找org.springframework.boot.Bootstrapper
找ApplicationContextInitializer;去spring.factories找 ApplicationContextInitializer,保存在 List<ApplicationContextInitializer<?>> initializers
找ApplicationListener应用监听器。去spring.factories找ApplicationListener,保存在List<ApplicationListener<?>> listeners

简单来说,应用创建的过程,就是把一些关键的主键去spring.factories文件中给我们把信息读取出来,提前保存到springapplication里

無題
8 声望1 粉丝

沉迷java无法自拔。