[springboot 소스 코드 판독 시리즈] (5. springboot 시작 에 대한 분석 META - INF / spring. factories 의 SpringFactories Loader 상세 해석)
13480 단어 Springboot소스 코드springboot
그럼 SpringFactories Loader 의 신비 로 운 베일 을 벗 기 겠 습 니 다. 설명 은 모두 주석 에 있 습 니 다.
배 울 만 한 것 은 그의 이러한 디자인 이념 이다. 지 정 된 규범 을 통 해 사용자 에 게 확장 을 제공 하고 springboot 의 시동 원리 도 이렇게 실현 된다.
에센스 추출: ConcurrentMap (스 레 드 가 안전 한 map 집합) 은 캐 시 cache 로 서 구조 기 를 통 해 인 스 턴 스 (access bleConstructor) 를 만 들 고 isAssignable From 는 하위 클래스 인지 판단 합 니 다 (isAssignable From 와 instanceof 키워드 의 차이 점)
package org.springframework.core.io.support;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.io.UrlResource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* 。spring
*
* springfactoresloader META-INF/spring.factories ,
* , key value,
* spring.factories properties , ,
*
* :
* example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
*
*/
public final class SpringFactoriesLoader {
/**
* 로 컬 공장 파일,
* 여러 jar 에 존재 할 수 있 습 니 다. 즉, 그 는 모든 jar 를 스 캔 한 다음 에 모든 META - INF / spring. factories 파일 을 분석 합 니 다.
* 공장 을 만 들 고 모든 value 를 예화 합 니 다.
*/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
/ / 로그 프레임 워 크
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
/ / map 를 정의 합 니 다. 그 중에서 key 는 ClassLoader 이 고 value 는 MultiValueMap 입 니 다.
/ / MultiValueMap 통합 자체 맵
/ / ConcurrentReference HashMap 은 ConcurrentMap, 즉 하나의 라인 이 안전 한 맵 으로 통합 되 어 있 습 니 다
private static final Map> cache = new ConcurrentReferenceHashMap<>();
/ / 공 삼 구조 함수
private SpringFactoriesLoader() {
}
/**
* classLoader 를 통 해 각 jar 패키지 의 classpath 아래 META - INF / spring. factories 에서 key - value 값 을 불 러 오고 분석 한 다음 주어진 유형의 공장 을 만 듭 니 다.
*
* 돌아 온 공장 은 AnnotationAware Order Comparator 를 통 해 순 위 를 매 겼 습 니 다.
* AnnotationAware Order Comparator 는 @ Order 주석 을 통 해 위의 값 을 정렬 하고 값 이 높 을 수록 뒤로 배열 합 니 다.
*
* 사용자 정의 실례 화 정책 이 필요 하 다 면 loadFactory Names 방법 으로 모든 등록 공장 이름 을 가 져 오 십시오.
*
* @ param factory Type 인터페이스 또는 추상 적 인 클래스 대상
* @ param classLoader 에서 불 러 오 는 클래스 로 더 (null 일 수 있 습 니 다. null 일 경우 기본 값 을 사용 합 니 다)
* @ throws IllegalArgument Exception 공장 구현 클래스 를 불 러 올 수 없 거나 공장 을 예화 하 는 중 오류 가 발생 하면 IllegalArgument Exception 이상 을 던 집 니 다.
*/
public static List loadFactories(Class factoryType, @Nullable ClassLoader classLoader) {
/ / 우선 들 어 오 는 인터페이스 나 추상 적 인 클래스 의 대상 이 비어 있 으 면 안 된다 고 단언 합 니 다.
Assert.notNull(factoryType, "'factoryType' must not be null");
/ / 들 어 오 는 classLoader 를 classLoaderToUse 에 할당 합 니 다.
/ / classLoaderToUse 가 비어 있 는 지, 비어 있 는 지 판단 하려 면 기본 SpringFactoriesLoader 의 classLoader 를 사용 하 십시오.
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
/ / 모든 META - INF / spring. factories 를 불 러 오고 설정 한 factory Names 를 가 져 옵 니 다.
List factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
}
List result = new ArrayList<>(factoryImplementationNames.size());
/ / 반 사 를 통 해 모든 설정 을 예화 합 니 다.
for (String factoryImplementationName : factoryImplementationNames) {
result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
/**
* 주어진 클래스 로 더 를 사용 하여 META - INF / spring. factories 에서 주어진 유형의 공장 을 불 러 오 는 완전 한정 클래스 입 니 다.
* @ param factory Type 인터페이스 또는 추상 적 인 클래스 대상
*
* @ param classLoader classLoader 가 불 러 오 는 클래스 로 더 (null 일 수 있 습 니 다. null 일 경우 기본 값 을 사용 합 니 다)
*
* @ throws IllegalArgument Exception 공장 이름 을 불 러 오 는 중 오류 가 발생 하면
* @see #loadFactories
*/
public static List loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader) {
/ / Class 대상 을 통 해 전체 한정 클래스 이름 가 져 오기
String factoryTypeName = factoryType.getName();
/ / loadSpringFactory 방법 은 모든 springFactory 를 얻 는 것 입 니 다.
/ / getOrDefault 는 key 를 통 해 해당 하 는 클래스 의 집합 을 가 져 옵 니 다. value 는 쉼표 로 구분 되 어 있 기 때문에 여러 개 를 가 질 수 있 기 때문에 list 입 니 다.
/ / getOrDefault 가 존재 하면 되 돌려 주 고 존재 하지 않 으 면 기본 값 으로 되 돌려 줍 니 다.
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
/ / 모든 springFactory 불 러 오기
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
/ / 우선 cache 에서 가 져 옵 니 다. classLoader 에 따 르 면,
/ / cache 는 ClassLoader 를 key 로 합 니 다. 정적 final 수식 입 니 다. 전체 응용 프로그램 은 하나 뿐 입 니 다.
MultiValueMap result = cache.get(classLoader);
/ / null 이면 아직 불 러 오지 않 았 음 을 증명 합 니 다. 비어 있 지 않 으 면 추가 합 니 다.
if (result != null) {
return result;
}
try {
/ / 세 개의 표현 식 으로 인자 classLoader 가 비어 있 는 지 판단 합 니 다. 비어 있 지 않 으 면 들 어 오 는 classLoader 를 사용 하여 META - INF / spring. factories 를 가 져 옵 니 다.
/ / 비어 있 으 면 시스템 의 classLoader 를 사용 하여 META - INF / spring. factories 를 가 져 옵 니 다.
/ / 아무튼 건장 성 이 강하 다.
Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
/ / 모든 META - INF / spring. factories 를 순환 해서 옮 겨 다 니 기
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
/ / 분석 속성
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
/ / 모든 키 를 result 에 넣 기
for (Map.Entry entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
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);
}
}
/ / 실례 화학 공장, 근거
@SuppressWarnings("unchecked")
private static T instantiateFactory(String factoryImplementationName, Class factoryType, ClassLoader classLoader) {
try {
/ / 전 한정 클래스 명 에 따라 반사 로 Class 대상 획득
Class factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);
/ / 가 져 온 Class 대상 이 factory Type 에서 왔 는 지 판단 합 니 다.
/ / 구체 적 으로 말 하면 우리 가 설정 한 spring. factories 의 권한 클래스 이름 에 대응 하 는 클래스 가 대응 하 는 하위 클래스 나 실현 클래스 인지 판단 하 는 것 입 니 다.
예 를 들 면
// org.springframework.context.ApplicationContextInitializer=\
// org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
// org.springframework.boot.context.ContextIdApplicationContextInitializer,
/ / 그러면 Configuration Warnings Application ContextInitializer 와 ContextIdApplication ContextInitializer 가 Application ContextInitializer 의 하위 클래스 인지 검증 합 니 다.
// isAssignable From () 방법 과 instanceof 키워드 의 차 이 는 다음 과 같은 두 가지 로 요약 된다.
// isAssignable From () 방법 은 클래스 계승 의 측면 에서 판단 하고 인 스 턴 스 of 키 워드 는 인 스 턴 스 계승 의 측면 에서 판단 합 니 다.
// isAssignable From () 방법 은 특정한 종류의 부모 클래스 인지 아 닌 지 를 판단 하 는 것 이 며, instanceof 키 워드 는 특정한 종류의 하위 클래스 인지 아 닌 지 를 판단 하 는 것 입 니 다.
/ / 그렇지 않 으 면 저장 합 니 다.
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);
}
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[MeU] Hashtag 기능 개발➡️ 기존 Tag 테이블에 존재하지 않는 해시태그라면 Tag , tagPostMapping 테이블에 모두 추가 ➡️ 기존에 존재하는 해시태그라면, tagPostMapping 테이블에만 추가 이후에 개발할 태그 기반 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.