走进 Spring Boot 第二步之 SpringApplicaiton 构造函数

Spring Boot Java About 8,781 words

Spring Boot 启动类

SpringApplication.run

@SpringBootApplication
public class DemoApplication {

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

SpringApplication

构造函数

resourceLoader参数为空,primarySources参数为DemoApplication的字节码类。

//SpringApplication类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    // primarySources可变参数为单一的一个DemoApplication
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //判断DemoApplication的应用类型
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //从Spring工厂示例中获得Initializers
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //从Spring工厂示例中获得Listeners
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //判断应用main方法入口
    this.mainApplicationClass = deduceMainApplicationClass();
}

deduceFromClasspath

从类路径推断应用类型,先判断是否是REACTIVE,若不是,则判断SERVLET_INDICATOR_CLASSES数组中的两个全路径类名能否加载,如果能加载则是SERVLET应用,否则就是NONE

//WebApplicationType类
private static final String[] SERVLET_INDICATOR_CLASSES = { 
            "javax.servlet.Servlet",
            "org.springframework.web.context.ConfigurableWebApplicationContext" 
};
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

static WebApplicationType deduceFromClasspath() {
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
            && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
            && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}

ClassUtilsisPresent判断能否更具全路径名称加载该类,捕获了ClassNotFoundException异常

//ClassUtils类
public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
    try {
        forName(className, classLoader);
        return true;
    }
    catch (IllegalAccessError err) {
        throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +
                className + "]: " + err.getMessage(), err);
    }
    catch (Throwable ex) {
        // Typically ClassNotFoundException or NoClassDefFoundError...
        return false;
    }
}

public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
        throws ClassNotFoundException, LinkageError {

    Assert.notNull(name, "Name must not be null");

    // 省略了判断字节码类是否原子类型

    ClassLoader clToUse = classLoader;
    if (clToUse == null) {
        clToUse = getDefaultClassLoader();
    }
    try {
        return Class.forName(name, false, clToUse);
    }
    catch (ClassNotFoundException ex) {
        throw ex;
    }
}

getSpringFactoriesInstances

根据全路径名从Spring工厂中获得实例。

//SpringApplication类
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    // 获取classLoader,非重点,不展开
    ClassLoader classLoader = getClassLoader();
    // 使用名称确保唯一来防止重复
    // 加载META-INF/spring.factories配置的类
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 创建实例
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    //根据注解来排序
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

//SpringFactoriesLoader类
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    // 根据key获取对应的value
    // Initializers/Listeners的key正好都是interface基类
    return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    //省略了从缓存取

    try {
        // 加载META-INF/spring.factories配置文件
        Enumeration<URL> urls = (classLoader != null ?
                classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        result = new LinkedMultiValueMap<>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            UrlResource resource = new UrlResource(url);
            // 读取配置信息,PropertiesLoaderUtils为Spring工具类用于读取配置文件,此处不展开
            // META-INF/spring.factories配置文件中的反斜杠\会被解析为一行,了解更多Java Properties类可参见先前文章
            Properties properties = PropertiesLoaderUtils.loadProperties(resource);
            for (Map.Entry<?, ?> entry : properties.entrySet()) {
                String factoryClassName = ((String) entry.getKey()).trim();
                // 将逗号分隔的value值解析为String数组
                // 遍历数组放入LinkedMultiValueMap对象中,LinkedMultiValueMap实际就是一个LinkedHashMap
                for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                    result.add(factoryClassName, factoryName.trim());
                }
            }
        }
        // 配置信息放入缓存
        cache.put(classLoader, result);
        return result;
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}

META-INF/spring.factories中的InitializersListeners配置

# Application Context Initializers
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

# Application Listeners
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

createSpringFactoriesInstances

使用反射初始化各个InitializersListeners等。

//SpringApplication
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
    List<T> instances = new ArrayList<>(names.size());
    // 遍历,使用反射初始化类,BeanUtils等反射初始化类等此处不展开
    for (String name : names) {
        try {
            Class<?> instanceClass = ClassUtils.forName(name, classLoader);
            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;
}

deduceMainApplicationClass

主动new出一个运行时异常,根据堆栈信息获取main方法对应的堆栈元素,根据该堆栈元素来获取main方法所在的类名。

//SpringApplication
private Class<?> deduceMainApplicationClass() {
    try {
        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;
}

流程总结

  1. 判断应用类型
  2. 获得Initializers实例集合
  3. 获得Listeners实例集合
  4. 获得main方法所在类
Views: 4,601 · Posted: 2020-04-04

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb/LiteNote

扫描下方二维码关注公众号和小程序↓↓↓

扫描下方二维码关注公众号和小程序↓↓↓


Today On History
Browsing Refresh