SpringFactoriesLoader 源碼分析

SpringFactoriesLoader

  • Author: HuiFer

  • 源碼閱讀倉庫: SourceHot-spring-boot

  • 全路徑 : org.springframework.core.io.support.SpringFactoriesLoader

  • 測試類 : org.springframework.core.io.support.SpringFactoriesLoaderTests

loadFactories

  • **加載並實例化工廠 **
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
		Assert.notNull(factoryType, "'factoryType' must not be null");
		ClassLoader classLoaderToUse = classLoader;
		if (classLoaderToUse == null) {
			classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
		}
		// 工廠實現類名稱
		List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
		if (logger.isTraceEnabled()) {
			logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
		}
		List<T> result = new ArrayList<>(factoryImplementationNames.size());
		for (String factoryImplementationName : factoryImplementationNames) {
			// 將實例化的工廠放入結果集合
			result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
		}
		// 排序
		AnnotationAwareOrderComparator.sort(result);
		return result;
	}

loadSpringFactories

  • 獲取接口的實現類名
	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
			// 找 META-INF/spring.factories
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				// 獲取 路由地址
				URL url = urls.nextElement();
				// url 解析
				UrlResource resource = new UrlResource(url);
				// Properties 解析
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				// 循環解析結果
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						// 放入list
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
			// 放入緩存
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
													   FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

  • 存放在 測試目錄下的META-INF/spring.factories

    org.springframework.core.io.support.DummyFactory =\
    org.springframework.core.io.support.MyDummyFactory2, \
    org.springframework.core.io.support.MyDummyFactory1
    
    java.lang.String=\
    org.springframework.core.io.support.MyDummyFactory1
    
    org.springframework.core.io.support.DummyPackagePrivateFactory=\
    org.springframework.core.io.support.DummyPackagePrivateFactory
    
    
  • Enumeration<URL> urls 變量存放的是 掃描到的META-INF/spring.factories 路徑

  • while 代碼簡單描述

    1. 獲取文件路徑
    2. 文件路徑解析
    3. 讀取文件 Properties 解析
    4. 放入返回結果
    5. 放入緩存

instantiateFactory

@SuppressWarnings("unchecked")
private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) {
   try {
      Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);
      if (!factoryType.isAssignableFrom(factoryImplementationClass)) {
         throw new IllegalArgumentException(
               "Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]");
      }
      return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance();
   }
   catch (Throwable ex) {
      throw new IllegalArgumentException(
            "Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]",
            ex
      );
   }
}
  • 反射創建
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章