zoukankan      html  css  js  c++  java
  • springboot(十四) 源码分析 —— SpringApplication的创建

    SpringApplication的创建 

    基于 2.2.9.RELEASE的版本,启动项目debug

    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
    }
        public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
            return new SpringApplication(primarySources).run(args);
        }

    run方法最后的走到SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) 来实例化我们的SpringApplication

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
      // 1.1
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources,
    "PrimarySources must not be null");
    // 1.2
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 1.3
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 1.4 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.
    class));
    // 1.5 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.
    class));
    // 1.6
    this.mainApplicationClass = deduceMainApplicationClass(); }

    1.1 resourceLoader 属性,资源加载器

    此处debug显示为null;感兴趣的小伙伴可以看一看:Spring 统一资源加载策略(https://blog.csdn.net/cuiwjava/article/details/108940768

     

    1.2 primarySources 属性,主要的 Java Config 类的数组

    在此处就是对应我们的启动类 DemoApplication 类。

    1.3 webApplicationType 属性,调用 WebApplicationType#deduceFromClasspath() 方法,通过 classpath ,判断 Web 应用类型

        static WebApplicationType deduceFromClasspath() {
          // WebApplicationType.REACTIVE 类型
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; }
          // WebApplicationType.NONE 类型
    for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } }
        // WebApplicationType.SERVLET 类型。可以酱紫的判断的原因是,引入 Spring MVC 时,如果是内嵌的 Web 应用,会引入 Servlet 类。
    return WebApplicationType.SERVLET; }

    1.4 initializers 属性,ApplicationContextInitializer 数组

    通过 #getSpringFactoriesInstances(Class<T> type) 方法,进行获得 ApplicationContextInitializer 类型的对象数组。

        private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
            ClassLoader classLoader = getClassLoader();
            // 1.4.1 加载指定类型对应的,在 `META-INF/spring.factories` 里的类名的数组
            Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
         // 1.4.2 创建对象们 List
    <T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
          // 1.4.3 排序对象们 AnnotationAwareOrderComparator.sort(instances);
    return instances; }

    1.4.1,调用 SpringFactoriesLoader#loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) 方法,加载指定类型对应的,在 META-INF/spring.factories 里的类名的数组。在 META-INF/spring.factories 文件中,会以 KEY-VALUE 的格式,配置每个类对应的实现类们。关于 SpringFactoriesLoader 的该方法,我们就不去细看了。

    1.4.2,调用 #createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) 方法,创建对象们。代码如下:

        private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
                ClassLoader classLoader, Object[] args, Set<String> names) {
            List<T> instances = new ArrayList<>(names.size());
            for (String name : names) {
                try {
              // 获得 name 对应的类 Class
    <?> instanceClass = ClassUtils.forName(name, classLoader);
              // 判断类是否实现自 type 类 Assert.isAssignable(type, instanceClass);
              // 获得构造方法 Constructor
    <?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
              // 创建对象 T instance
    = (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex); } } return instances; }

    1.4.3,调用 AnnotationAwareOrderComparator#sort(List<?> list) 方法,排序对象们。例如说,类上有 @Order 注解。 

    当前Demo是在 Spring MVC 的环境下,initializers 属性的结果如下图:

     1.5 listeners 属性,ApplicationListener 数组

    也是通过 #getSpringFactoriesInstances(Class<T> type) 方法,进行获得 ApplicationListener 类型的对象数组。listeners 属性的结果如下图:

     1.6 mainApplicationClass 属性

    调用 #deduceMainApplicationClass() 方法,获得是调用了哪个 #main(String[] args) 方法,代码如下:

        private Class<?> deduceMainApplicationClass() {
            try {
            // 获得当前 StackTraceElement 数组 StackTraceElement[] stackTrace
    = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) {
              // 判断哪个执行了 main 方法
    if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }

    此处对应的就是我们Demo的启动类,DemoApplication,到处我们SpringApplication创建完成。代码不是很复杂,主要部分是加载META-INF/spring.factories里面的资源并实例化。

  • 相关阅读:
    python---基础部分
    自动化测试---Selenium IDE安装及操作
    自动化测试---Selenium IDE概念
    自动化测试----概念
    jmeter---后端监听器
    jmeter---分布式测试
    jmeter---runtime控制器
    什么是 MyBatis 的接口绑定,有什么好处?
    接口绑定有几种实现方式,分别是怎么实现的?
    Apache Shiro 的三大核心组件
  • 原文地址:https://www.cnblogs.com/hlkawa/p/14095440.html
Copyright © 2011-2022 走看看