springboot啟動的applicationContext的型別選擇
首先,一共有三種型別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;
相關文章
- (五)SpringBoot啟動過程的分析-重新整理ApplicationContextSpring BootAPPContext
- (四)SpringBoot啟動過程的分析-預處理ApplicationContextSpring BootAPPContext
- 選擇適合的型別判斷方式型別
- mysql 貨幣型別 選擇MySql型別
- 如何選擇合適的SSL證書型別型別
- 根據需要的圖表型別選擇echarts對應的series型別型別Echarts
- React 進階之選擇合適的元件型別React元件型別
- 高效能Mysql(第3版)_資料型別的選擇_整數型別MySql資料型別
- BeanFactory 和 ApplicationContext 的區別BeanAPPContext
- 你的遊戲型別選擇早被設計師掌握遊戲型別
- SpringBoot 使用ApplicationContext 及 getbean的兩種方式Spring BootAPPContextBean
- js選擇物件和jq選擇物件的區別JS物件
- SpringBoot原理之二_ApplicationContextSpring BootAPPContext
- 設計表時,如何選擇正確的資料型別資料型別
- dom選擇方法的區別
- css選擇器有哪幾種型別CSS型別
- MySQL 資料型別分類和選擇MySQL 資料型別
- SpringBoot 啟動類的原理Spring Boot
- 如何選擇各種型別資料庫?- Raj型別資料庫
- SSL證書有哪些型別?如何去選擇?型別
- SpringBoot應用使用自定義的ApplicationContext實現類Spring BootAPPContext
- 《高效能MySQL》筆記——MySQL建表資料型別的選擇MySql筆記資料型別
- 如何正確選擇ARM核心板、ARM工控板的儲存型別?型別
- Task3&Task4(函式的定義與呼叫,返回型別的選擇)函式型別
- GRUB配置預設選擇上一次的啟動項
- springboot實現分享型別的專案Spring Boot型別
- go slice/map型別 排序(選擇排序演算法)Go型別排序演算法
- ERP系統型別大對比,切勿盲目選擇型別
- springboot最新穩定版本、springcloud對應版本的選擇Spring BootGCCloud
- ApplicationContext 與 BeanFactory 區別APPContextBean
- 機房IP和家庭IP:如何選擇最適合你的網路型別型別
- 淺談程式語言型別的強型別,弱型別,動態型別,靜態型別型別
- 網易雲音樂 DBA 談 TiDB 選型:效率的選擇TiDB
- CBO計算與資料型別的選擇(兼談日期、字元、數字三種型別的直方圖生成原理和使用)資料型別字元直方圖
- spring beanFactory與ApplicationContext區別SpringBeanAPPContext
- 如何選擇註冊公眾號的型別?如何進行新媒體運營型別
- SpringBootApplication是如何啟動Tomcat的? | 破解SpringBoot Tomcat啟動之謎 !Spring BootAPPTomcat
- Tomcat在SpringBoot中是如何啟動的TomcatSpring Boot