美文网首页
03--SpringBoot启动之应用类型推断

03--SpringBoot启动之应用类型推断

作者: 闲来也无事 | 来源:发表于2018-08-19 00:10 被阅读20次

前面介绍了SpringBoot的启动流程,接下来分析启动流程中的细节,首先是启动时对应用类型的判断

1. SpringBoot中的应用类型介绍

打开WebApplicationType枚举,可以看到SpringBoot中共有三种应用类型

public enum WebApplicationType {
    //应用程序不应作为Web应用程序运行,也不应启动嵌入式Web服务器。
    NONE,
    //应用程序应作为基于servlet的Web应用程序运行,并应启动嵌入式servlet Web服务器。
    SERVLET,
    //应用程序应作为响应式Web应用程序运行,并应启动嵌入式响应式Web服务器。
    REACTIVE
}

接上文02--SpringBoot启动源码简单分析创建SpringApplication实例中
this.webApplicationType = deduceWebApplicationType();

2. 推断SpringBoot中的应用类型

//推断应用类型
private WebApplicationType deduceWebApplicationType() {
    //REACTIVE_WEB_ENVIRONMENT_CLASS可加载且MVC_WEB_ENVIRONMENT_CLASS和JERSEY_WEB_ENVIRONMENT_CLASS不能加载,则为响应式web应用
    if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
            && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
            && !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
        return WebApplicationType.REACTIVE;
    }
    //Servlet和ConfigurableWebApplicationContext不能加载则为非web应用类型
    for (String className : WEB_ENVIRONMENT_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    //排除上述两种类型,推断当前应用为servlet类型
    return WebApplicationType.SERVLET;
}

//isPresent判断的类型如下
private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String JERSEY_WEB_ENVIRONMENT_CLASS = "org.glassfish.jersey.server.ResourceConfig";

private static final String[] WEB_ENVIRONMENT_CLASSES = {"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};

ClassUtils.javaorg.springframework.util下的工具类,不是JDK的工具类,我们来看其中的
isPresent()方法

//判断className类是否存在且可以被加载
public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
    try {
        //如果className可以被加载,返回true
        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...
        //className加载失败,返回false
        return false;
    }
}

分析forName(className, classLoader);方法

/**
  替换Class.forName()它也会返回基元的类实例(例如“int”)和数组类名(例如“String []”)。
  此外,它还能够以Java源代码样式解析内部类名(例如“java.lang.Thread.State”而不      
  是“java.lang.Thread $ State”)。
  如果找不到或者无法加载类则抛出异常
*/
public static Class<?> forName(String name, @Nullable ClassLoader classLoader) throws ClassNotFoundException, LinkageError {

    Assert.notNull(name, "Name must not be null");
    //根据JVM的基本类命名规则,将给定的类名解析为基本类(如果适用)。
    Class<?> clazz = resolvePrimitiveClassName(name);
    //从commonClassCache缓存Map中获取,如果存在则返回
    if (clazz == null) {
        clazz = commonClassCache.get(name);
    }
    if (clazz != null) {
        return clazz;
    }

    // "java.lang.String[]" style arrays
    if (name.endsWith(ARRAY_SUFFIX)) {
        String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
        Class<?> elementClass = forName(elementClassName, classLoader);
        return Array.newInstance(elementClass, 0).getClass();
    }

    // "[Ljava.lang.String;" style arrays
    if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
        String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
        Class<?> elementClass = forName(elementName, classLoader);
        return Array.newInstance(elementClass, 0).getClass();
    }

    // "[[I" or "[[Ljava.lang.String;" style arrays
    if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
        String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length());
        Class<?> elementClass = forName(elementName, classLoader);
        return Array.newInstance(elementClass, 0).getClass();
    }
    
    //获取ClassLoader
    ClassLoader clToUse = classLoader;
    if (clToUse == null) {
        clToUse = getDefaultClassLoader();
    }
    try {
        //如果ClassLoader不为空则使用ClassLoader加载类,否则使用Class类来加载类
        return (clToUse != null ? clToUse.loadClass(name) : Class.forName(name));
    }
    catch (ClassNotFoundException ex) {
        int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
        if (lastDotIndex != -1) {
            String innerClassName = name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
            try {
                return (clToUse != null ? clToUse.loadClass(innerClassName) : Class.forName(innerClassName));
            }
            catch (ClassNotFoundException ex2) {
                // Swallow - let original exception get through
            }
        }
        throw ex;
    }
}

//获取ClassLoader
public static ClassLoader getDefaultClassLoader() {
    ClassLoader cl = null;
    try {
        //首先尝试获得线程上下文类加载器
        cl = Thread.currentThread().getContextClassLoader();
    }
    catch (Throwable ex) {
        // Cannot access thread context ClassLoader - falling back...
    }    
    if (cl == null) {
        //如果没有获取到线程上下文类加载器,则使用当前类的类加载器
        cl = ClassUtils.class.getClassLoader();
        if (cl == null) {
            // getClassLoader() returning null indicates the bootstrap ClassLoader
            try {
                //如果当前类的类加载器也没有获取到,则使用bootstrap ClassLoader
                cl = ClassLoader.getSystemClassLoader();
            }
            catch (Throwable ex) {
                // Cannot access system ClassLoader - oh well, maybe the caller can live with null...
            }
        }
    }
    return cl;
}

通过上面的分析,我们就可以得出当前的应用的具体类型

相关文章

网友评论

      本文标题:03--SpringBoot启动之应用类型推断

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