자바 SPI 07-SPI 프로필 자동 생 성 방법
7744 단어 spi
spi 01-pi 가 뭐 예요?입문 사용
spi 02-pi 의 실전 해결 slf4j 패키지 충돌 문제
spi 03-pi jdk 원본 코드 분석 실현
spi 04-pi dubbo 원본 코드 분석 실현
spi 05-dubbo adaptive extension 적응 확장
spi 06-자필 로 SPI 프레임 워 크 구현
spi 07-SPI 프로필 자동 생 성 방식
돌이켜보다
지난 절 에 우 리 는 스스로 간단 한 버 전의 SPI 를 실현 했다.
이 절 에서 우 리 는 함께 구 글 auto 와 유사 한 도 구 를 실현 합 니 다.
데모 사용
클래스 실현
정의 인터페이스
@SPI
public interface Say {
void say();
}
@SPIAuto("bad")
public class SayBad implements Say {
@Override
public void say() {
System.out.println("bad");
}
}
@SPIAuto("good")
public class SayGood implements Say {
@Override
public void say() {
System.out.println("good");
}
}
실행 효과
집행
mvn clean install
후.META-INF/services/
폴 더 에서 파일 자동 생 성com.github.houbb.spi.bs.spi.Say
내용 은 다음 과 같다.good=com.github.houbb.spi.bs.spi.impl.SayGood
bad=com.github.houbb.spi.bs.spi.impl.SayBad
코드 구현
이 부분 은 주로 컴 파일 할 때 주 해 를 사용 하 는데 난이도 가 상대 적 으로 높다.
모든 원본 코드 가 lombok-ex 에서 시작 되 었 습 니 다.
주해 정의
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE})
@Documented
public @interface SPIAuto {
/**
*
* @return
* @since 0.1.0
*/
String value() default "";
/**
*
* @return
* @since 0.1.0
*/
String dir() default "META-INF/services/";
}
사실 여기 dir()는 노출 을 하지 않 아 도 되 고 여기 후기 에 더욱 유연 한 확장 을 하고 싶 어서 잠 정적 으로 이렇게 정 했다.
핵심 실현
@SupportedAnnotationTypes("com.github.houbb.lombok.ex.annotation.SPIAuto")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class SPIAutoProcessor extends BaseClassProcessor {
@Override
public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
java.util.List classList = super.getClassList(roundEnv, getAnnotationClass());
Map> spiClassMap = new HashMap<>();
for (LClass lClass : classList) {
String spiClassName = getSpiClassName(lClass);
String fullName = lClass.classSymbol().fullname.toString();
if(StringUtil.isEmpty(spiClassName)) {
throw new LombokExException("@SPI class not found for class: "
+ fullName);
}
Pair aliasAndDirPair = getAliasAndDir(lClass);
String newLine = aliasAndDirPair.getValueOne()+"="+fullName;
// : +
String filePath = aliasAndDirPair.getValueTwo()+spiClassName;
Set lineSet = spiClassMap.get(filePath);
if(lineSet == null) {
lineSet = new HashSet<>();
}
lineSet.add(newLine);
spiClassMap.put(filePath, lineSet);
}
//
generateNewFiles(spiClassMap);
return true;
}
}
전체 흐름:
(1)모든 종 류 를 옮 겨 다 니 며
SPIAuto
주석 이 있 는 종 류 를 찾 습 니 다.(2)클래스 정보,주해 정보 에 따라 모든 클래스 를 SPI 인터페이스 로 나 누 어 map 에 저장 합 니 다.
(3)맵 의 정보 에 따라 해당 하 는 프로필 정 보 를 생 성 합 니 다.
SPI 인터페이스 방법 이름 가 져 오기
현재 클래스 의 모든 인 터 페 이 스 를 가 져 오고 첫 번 째 로
@SPI
표 시 된 인 터 페 이 스 를 찾 아 되 돌려 줍 니 다./**
* spi
* @param lClass
* @return
* @since 0.1.0
*/
private String getSpiClassName(final LClass lClass) {
List typeList = lClass.classSymbol().getInterfaces();
if(null == typeList || typeList.isEmpty()) {
return "";
}
//
SPIAuto auto = lClass.classSymbol().getAnnotation(SPIAuto.class);
for(Type type : typeList) {
Symbol.ClassSymbol tsym = (Symbol.ClassSymbol) type.tsym;
//TOOD: 。
if(tsym.getAnnotation(SPI.class) != null) {
return tsym.fullname.toString();
}
}
return "";
}
주석 정보 가 져 오기
주 해 는 주로 더욱 유연 하 게 지정 하고 상대 적 으로 간단 하 며 다음 과 같이 실현 하기 위해 서 이다.
클래스 에 대한 별명 은 기본적으로 클래스 이니셜 소문 자로 spring 과 유사 합 니 다.
private Pair getAliasAndDir(LClass lClass) {
//
SPIAuto auto = lClass.classSymbol().getAnnotation(SPIAuto.class);
//1.
String fullClassName = lClass.classSymbol().fullname.toString();
String simpleClassName = fullClassName.substring(fullClassName.lastIndexOf("."));
String alias = auto.value();
if(StringUtil.isEmpty(alias)) {
alias = StringUtil.firstToLowerCase(simpleClassName);
}
return Pair.of(alias, auto.dir());
}
파일 생 성
파일 생 성 은 가장 핵심 적 인 배 고 픔 을 실현 하 는 부분 입 니 다.주로 구 글 의 auto 실현 을 참고 합 니 다.
사실 주요 난점 은 파일 의 경 로 를 가 져 오 는 것 입 니 다.이 점 은 컴 파일 할 때 주석 이 번 거 로 워 서 코드 가 많이 쓰 입 니 다.
/**
*
* key:
* value:
* @param spiClassMap
* @since 0.1.0
*/
private void generateNewFiles(Map> spiClassMap) {
Filer filer = processingEnv.getFiler();
for(Map.Entry> entry : spiClassMap.entrySet()) {
String fullFilePath = entry.getKey();
Set newLines = entry.getValue();
try {
// would like to be able to print the full path
// before we attempt to get the resource in case the behavior
// of filer.getResource does change to match the spec, but there's
// no good way to resolve CLASS_OUTPUT without first getting a resource.
FileObject existingFile = filer.getResource(StandardLocation.CLASS_OUTPUT, "",fullFilePath);
System.out.println("Looking for existing resource file at " + existingFile.toUri());
Set oldLines = readServiceFile(existingFile.openInputStream());
System.out.println("Looking for existing resource file set " + oldLines);
//
newLines.addAll(oldLines);
writeServiceFile(newLines, existingFile.openOutputStream());
return;
} catch (IOException e) {
// According to the javadoc, Filer.getResource throws an exception
// if the file doesn't already exist. In practice this doesn't
// appear to be the case. Filer.getResource will happily return a
// FileObject that refers to a non-existent file but will throw
// IOException if you try to open an input stream for it.
//
System.out.println("Resources file not exists.");
}
try {
FileObject newFile = filer.createResource(StandardLocation.CLASS_OUTPUT, "",
fullFilePath);
try(OutputStream outputStream = newFile.openOutputStream();) {
writeServiceFile(newLines, outputStream);
System.out.println("Write into file "+newFile.toUri());
} catch (IOException e) {
throw new LombokExException(e);
}
} catch (IOException e) {
throw new LombokExException(e);
}
}
}
기타
전체적인 사고방식 은 바로 이렇다.그리고 일부 세부 사항 은 여기 서 더 이상 전개 되 지 않 는 다.
github lombok-ex 에 오신 것 을 환영 합 니 다.
도움 이 된다 면 스타 에 게 작가 님 을 격려 해 주세요~
진보 적 사고
생태 는 구조의 일부분 으로서 주로 사용자 에 게 편 의 를 제공 하기 위 한 것 이다.
실제로 이 도 구 는 더 유연 하 게 만 들 수 있 습 니 다.예 를 들 어 dubbo spi 에 spi 설정 파일 을 자동 으로 생 성 할 수 있 습 니 다.
참고 자료
AutoServiceProcessor
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
jdbc 클래스 캐리어, spi 서비스 메커니즘먼저 코드 를 실행 하고 my sql jdbc 구동 의 클래스 로드 (maven 프로젝트 는 jdbc 구동 의존 도 를 도 입 했 고 버 전 은 5.1.41) 를 살 펴 보 았 습 니 다. 부모 위임 모델 의 규칙 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.