SpringBoot啟動流程源碼分析( 二 )

復制

  • 若滿足類路徑(包括依賴jar包)中存在org.springframework.web.reactive.DispatcherHandler類 , 同時不存在org.springframework.web.servlet.DispatcherServlet類和org.glassfish.jersey.servlet.ServletContainer類則返回REACTIVE類型Web應用
  • 遍歷判斷類路徑中是否同時存在javax.servlet.Servlet類和org.springframework.web.context.ConfigurableWebApplicationContext類,滿足則返回SERVLET類型Web應用,否則返回非Web應用
加載spring.factories文件中配置的初始化器和監聽器通過調用SpringApplication#getSpringFactoriesInstances方法得到的返回值設置初始化器和監聽器屬性,傳入的參數分別為ApplicationContextInitializer類和ApplicationListener
/***根據傳入的type參數獲取類路徑META-INF/spring.factories文件中的自動配置初始化類集合@param type 類型@return Collection<T> 泛型集合*/private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {return this.getSpringFactoriesInstances(type, new Class[0]);}/***上一個方法的多參數重載方法* @param type 類型* @param parameterTypes 參數類型數組* @param args 參數數組*/private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = this.getClassLoader();// 通過SpringFactoriesLoader#loadFactoryNames方法獲取Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;}public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {String factoryClassName = factoryClass.getName();return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());}private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {// 如果緩存里有則直接從雙層緩存中獲取類加載器對應的結果MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);if (result != null) {return result;} else {// 緩存中沒有則去META-INF/spring.factories文件中加載并讀取解析try {Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");LinkedMultiValueMap result = new LinkedMultiValueMap();while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);Iterator var6 = properties.entrySet().iterator();while(var6.hasNext()) {Entry<?, ?> entry = (Entry)var6.next();String factoryClassName = ((String)entry.getKey()).trim();String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());int var10 = var9.length;for(int var11 = 0; var11 < var10; ++var11) {String factoryName = var9[var11];result.add(factoryClassName, factoryName.trim());}}}cache.put(classLoader, result);return result;} catch (IOException var13) {throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);}}}/*** 創建spring.factories文件中的初始化類實例集合*/private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {List<T> instances = new ArrayList(names.size());Iterator var7 = names.iterator();while(var7.hasNext()) {String name = (String)var7.next();try {// 調用反射工具類加載spring.factories文件中的初始化類Class<?> instanceClass = ClassUtils.forName(name, classLoader);Assert.isAssignable(type, instanceClass);Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);// 通過構造函數實例化類T instance = BeanUtils.instantiateClass(constructor, args);instances.add(instance);} catch (Throwable var12) {throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);}}return instances;}復制
推斷主應用類 private Class<?> deduceMainApplicationClass() {try {StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();StackTraceElement[] var2 = stackTrace;int var3 = stackTrace.length;for(int var4 = 0; var4 < var3; ++var4) {StackTraceElement stackTraceElement = var2[var4];if ("main".equals(stackTraceElement.getMethodName())) {return Class.forName(stackTraceElement.getClassName());}}} catch (ClassNotFoundException var6) {}return null;}復制
通過上面的源碼我們可以看到推斷主應用類是通過實例化一個運行時異常,并拿到該運行時異常的堆棧數組,然后循環遍歷堆棧數組,判斷堆棧元素的方法名是否為

推薦閱讀