자바 에서 JDK SPI 소스 코드 분석
19290 단어 자바
SPI 는 모두 Service Provider Interface 라 고 하 는데 일종 의 서비스 발견 메커니즘 으로 제3자 에 의 해 실현 되 거나 확 장 된 API 에 사용 된다.
JDK SPI 사용:
META-INF/services
디 렉 터 리 에 '인터페이스 전체 제한 이름' 이라는 이름 의 파일 을 만 듭 니 다. 인터페이스 '실현 클래스 의 전체 제한 이름' eg: 파일 이름: com. union. jd. SpiService 파일 내용: com.union.jd.ASpiServiceImpl
com.union.jd.BSpiServiceImpl
com.union.jd.CSpiServiceImpl
classpath
에서 java.util.ServiceLoader
도구 류 호출 실현 클래스 ServiceLoader<SpiService> serviceLoader = ServiceLoader.load(SpiService.class);
//ServiceLoader实现了Iterable,所以可以直接使用增强for遍历
for (DriverService driverService: serviceLoader){
System.out.println(driverService.getName());
}
2. ServiceLoader 소스 코드 분석
ServiceLoader
util 패키지 에서 계승 할 수 없 는 final
클래스 이 고 Iterable 인터페이스 iterator()
방법 을 실현 하여 이 인터페이스의 모든 실현 대상 에 사용 합 니 다.public final class ServiceLoader<S>implements Iterable<S> {...}
ServiceLoader
클래스 에서 상수 PREFIX
private static final String PREFIX = "META-INF/services/";
load
실현 //入参为接口的全限定名
public static <S> ServiceLoader<S> load(Class<S> service) {
//获取当前线程上下文类加载器
ClassLoader cl = Thread.currentThread().getContextClassLoader();
//调用重载方法
return ServiceLoader.load(service, cl);
}
//重载方法:参数1为接口的全限定名、参数二维当前线程上下文类加载器
public static <S> ServiceLoader<S> load(Class<S> service,ClassLoader loader)
{ //创建ServiceLoader对象
return new ServiceLoader<>(service, loader);
}
//ServiceLoader构造方法
private ServiceLoader(Class<S> svc, ClassLoader cl) {
//校验Class对象是否存在,赋值给变量service
service = Objects.requireNonNull(svc, "Service interface cannot be null");
//当"线程上下文类加载器"为null则获取"系统类加载器",赋值给变量loader
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
//security沙箱相关
acc = (System.getSecurityManager() != null) ? AccessController.getContext():null;
//调用reload方法
reload();
}
//reload方法
public void reload() {
//清空缓存的实例对象
providers.clear();
//创建LazyIterator内部类对象,赋值给lookupIterator属性,iterator()遍历就是对该属性遍历
lookupIterator = new LazyIterator(service, loader);
}
tip: 왜 load () 방법 에서 '현재 클래스 로 더' 나 '시스템 클래스 로 더' 가 아 닌 '스 레 드 컨 텍스트 클래스 로 더' 를 우선 사용 합 니까?[왜 Thread.currentThread().getContextClassLoader()
를 우선 사용 하고 직접 사용 하지 않 았 습 니까?시작 클래스 로 더 는 시스템 클래스 로 더 의 부모 로 더 입 니 다. 부모 로 더 가 하위 로 더 를 볼 수 없 기 때문에 클래스 를 불 러 올 수 없습니다. 따라서 '현재 클래스 로 더' 는 사용 할 수 없습니다.2. 많은 경우 에 로드 ServiceLoader.class.getClassLoader()
중의 jar 는 ClassLoader.getSystemClassLoader()
로 불 러 오 는 것 이 아니 라 ServiceLoader
ServiceLoader.class.getClassLoader()
를 용기 로 하 는 환경 에서 classpath
로 불 러 오 는 것 이 아니 라 AppClassLoader
java ee
에서 얻 은 것 은 tomcat
의 부모 로 더 입 니 다. 마찬가지 로 부모 로 더 가 서브 로 더 를 불 러 오 는 클래스 가 보이 지 않 아서 불 러 오지 않 습 니 다.따라서 우선 WebappClassLoader
을 사용 하고 '스 레 드 컨 텍스트 클래스 로 더' 가 null 일 때 만 사용 합 니 다 SystemClassLoader()
.private class LazyIterator implements Iterator<S> {...}
//ServiceLoader 的迭代器方法,lookupIterator是LazyIterator的实例
public Iterator<S> iterator() {
return new Iterator<S>() {
...
public boolean hasNext() {
...
return lookupIterator.hasNext();
}
public S next() {
...
return lookupIterator.next();
}
...
};
}
AppClassLoader
, WebappClassLoader
방법 은 Lazy Iterator 류 의 hasNextService (), nextService () 방법 public boolean hasNext() {
...
return hasNextService();
...
}
public S next() {
...
return nextService();
...
}
ContextClassLoader()
방법 으로 분석 하고 SystemClassLoader()
의 현재 인터페이스 파일 을 분석 하여 교체 기 현재 노드 의 실현 류 뒤에 실현 류 가 있 는 지 판단 합 니 다. 있 으 면 true 로 돌아 갑 니 다. 그렇지 않 으 면 false 로 돌아 갑 니 다. 실현 원 리 는 파일 읽 기 해석 private boolean hasNextService() {
...
}
hasNext()
방법 분석 private S nextService() {
...
//通过上面传的类加载器,反射获取当前实现类的class对象
c = Class.forName(cn, false, loader);
...
//类型转换
S p = service.cast(c.newInstance());
//添加到缓存中
providers.put(cn, p);
//返回实例对象
return p;
...
}
소스 코드 분석 을 통 해 SPI 의 본질은 반 사 를 통 해 구체 적 인 실현 클래스 인 스 턴 스 를 얻 는 것 임 을 알 수 있 습 니 다. 사용자 가
next()
디 렉 터 리 에서 설명 을 해 야 불 러 올 수 있 고 프레임 워 크 개발 에서 이러한 방식 으로 사용자 정의 로 실현 할 수 있 습 니 다.hasNextService()
의 자동화 설정 은 Spring SPI 도구 인 SpringFactoriesLoader 를 통 해 이 루어 진 것 이다.Spring 의 실현 은 JDK 의 사상 과 같 습 니 다. 본질은 모두 반사 체 제 를 통 해 SPI 라 고 할 수 있 지만 실현 이 일치 하지 않 습 니 다.
META-INF/services
, rt. jar 의 util 가방 에서 nextService()
이 며, org. spring from work. core. io. support 패키지 에서 이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.