欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

springboot启动的applicationContext的类型选择

程序员文章站 2022-05-25 12:35:35
...

首先,一共有三种类型AnnotationConfigServletWebServerApplicationContext,AnnotationConfigReactiveWebServerApplicationContext,AnnotationConfigApplicationContext。

springboot会根据webApplicationType的值来确定你加载哪一个applicationContext

 

/**
 * Strategy method used to create the {@link ApplicationContext}. By default this
 * method will respect any explicitly set application context or application context
 * class before falling back to a suitable default.
 * @return the application context (not yet refreshed)
 * @see #setApplicationContextClass(Class)
 */
protected ConfigurableApplicationContext createApplicationContext() {
   Class<?> contextClass = this.applicationContextClass;
   if (contextClass == null) {
      try {
         switch (this.webApplicationType) {
         case SERVLET:
            contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);//DEFAULT_SERVLET_WEB_CONTEXT_CLASS="org.springframework.boot."+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext"           
            break;
         case REACTIVE:
            contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);//DEFAULT_REACTIVE_WEB_CONTEXT_CLASS="org.springframework."+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"
            break;
         default:
            contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);//DEFAULT_CONTEXT_CLASS="org.springframework.context."+ "annotation.AnnotationConfigApplicationContext"
         }
      }
      catch (ClassNotFoundException ex) {
         throw new IllegalStateException(
               "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
      }
   }
   return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

而webApplicationType通过以下逻辑判断

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;
}

 

ClassUtils.isPresent(className, null)这个方法的调用功能是判断对应的className的类在不在指定的classLoader里面,此处传null,后台会调用ClassUtils.forName,会获取到默认的类加载器。代码如下:

/**
 * Replacement for {@code Class.forName()} that also returns Class instances
 * for primitives (e.g. "int") and array class names (e.g. "String[]").
 * Furthermore, it is also capable of resolving inner class names in Java source
 * style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State").
 * @param name the name of the Class
 * @param classLoader the class loader to use
 * (may be {@code null}, which indicates the default class loader)
 * @return a class instance for the supplied name
 * @throws ClassNotFoundException if the class was not found
 * @throws LinkageError if the class file could not be loaded
 * @see Class#forName(String, boolean, ClassLoader)
 */
public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
      throws ClassNotFoundException, LinkageError {

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

   Class<?> clazz = resolvePrimitiveClassName(name);
   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 clToUse = classLoader;
   if (clToUse == null) {
      clToUse = getDefaultClassLoader();
   }
   try {
      return Class.forName(name, false, clToUse);
   }
   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 Class.forName(innerClassName, false, clToUse);
         }
         catch (ClassNotFoundException ex2) {
            // Swallow - let original exception get through
         }
      }
      throw ex;
   }
}
如果不存在,会报异常退出,上层异常处理是返回false,
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;
   }
}

 

再往上回到

for (String className : SERVLET_INDICATOR_CLASSES) {
   if (!ClassUtils.isPresent(className, null)) {
      return WebApplicationType.NONE;
   }
}

返回false,则 return WebApplicationType.NONE;