Spring FactoriesLoader 메커니즘 실례 상세 설명

1.SpringFactoriesLoader 소개
1.1 SpringFactoriesLoader 소개
SpringFactoriesLoader 공장 로 딩 메커니즘 은 Spring 내부 에서 제공 하 는 약 속 된 로 딩 방식 으로 자바 spi 와 유사 하 며 모듈 의 META-INF/spring.factories 파일 에 Properties 형식(즉 key-value 형식)으로 설정 하면 해당 하 는 실 현 류 를 Spirng 용기 에 주입 할 수 있 습 니 다.
속성 형식:
key:전체 제한 이름(추상 클래스|인터페이스)
value:실현 입 니 다.여러 실현 은**쉼표**를 통 해 구 분 됩 니 다.
1.2 SpringFactoriesLoader 상용 방법
loadFactoryNames
classpath 에 있 는 모든 jar 패키지 의 모든 META-INF/spring.factories 속성 파일 을 읽 고 그 중에서 정 의 된 종류 인 factory Class 의 공장 클래스 를 찾 은 다음 이 공장 클래스 의 이름 목록 으로 돌아 갑 니 다.가방 이름 을 포함 하 는 모든 제한 이름 입 니 다.
loadFactories
classpath 에 있 는 모든 jar 패키지 의 모든 META-INF/spring.factories 속성 파일 을 읽 고 그 중에서 정 의 된 일치 하 는 유형의 factory Class 공장 클래스 를 찾 아 공장 클래스 의 대상/인 스 턴 스 를 만 들 고 이 공장 클래스 의 대상/인 스 턴 스 목록 을 되 돌려 줍 니 다.
1.3 loadFactory 흐름 도

2.SpringFactoriesLoader 소스 코드 분석
2.1 loadFactory Names 분석

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
  //             
  String factoryTypeName = factoryType.getName();
  //         META-INF/spring.factories     
  //               
  return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

//            ,        JAR   
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
  //          ,       
  MultiValueMap<String, String> result = cache.get(classLoader);
  if (result != null) {
    return result;
  }

  try {
    //    classpath     JAR      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()) {
      //       META-INF/spring.factories        Properties   ,          Properties              
      URL url = urls.nextElement();
      UrlResource resource = new UrlResource(url);
      Properties properties = PropertiesLoaderUtils.loadProperties(resource);
      for (Map.Entry<?, ?> entry : properties.entrySet()) {
        //        (            )
        String factoryTypeName = ((String) entry.getKey()).trim();
        //              ,       result   
        for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
          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);
  }
}

default V getOrDefault(Object key, V defaultValue) {
  V v;
  return (((v = get(key)) != null) || containsKey(key))
    ? v
    : defaultValue;
}
2.2 loadFactory 분석

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);
  //      Trace      ,         
  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;
}

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);
  }
}
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기