springboot啟動的applicationContext的型別選擇

xfgp02發表於2020-12-15

首先,一共有三種型別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;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相關文章