介紹
SPI是java提供的一種服務發現的標准,具體請看SPI介紹,但每次我們都需要自己創建services目錄,以及配置文件,google的autoservice就可以幫我們省去這一步。
使用
maven的依賴
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service-annotations</artifactId>
<version>1.0-rc6</version>
<optional>true</optional>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.0-rc6</version>
<optional>true</optional>
<scope>compile</scope>
</dependency>
定義接口
public interface UserService {
String userName();
}
定義接口實現,使用AutoService注解
@AutoService(UserService.class)
public class LocalUserService implements UserService {
@Override
public String userName() {
return "local user";
}
}
@AutoService(UserService.class)
public class RemoteUserService implements UserService {
@Override
public String userName() {
return "remote user";
}
}
調用
public class Client {
public static void main(String[] args) {
ServiceLoader<UserService> serviceLoader = ServiceLoader.load(UserService.class);
for (UserService userService : serviceLoader) {
System.out.println(userService.userName());
}
}
}
輸出結果為
local user
remote user
從編譯之后的目錄里可以看到已經生成了對應的配置文件
實現
@SupportedOptions({ "debug", "verify" })
public class AutoServiceProcessor extends AbstractProcessor {
@Override
// 處理
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
try {
return processImpl(annotations, roundEnv);
} catch (Exception e) {
// We don't allow exceptions of any kind to propagate to the compiler
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
fatalError(writer.toString());
return true;
}
}
//真正處理
private boolean processImpl(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//注解已經處理完畢了,創建配置文件
if (roundEnv.processingOver()) {
generateConfigFiles();
} else {
//處理注解
processAnnotations(annotations, roundEnv);
}
return true;
}
//處理注解
private void processAnnotations(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(AutoService.class);
for (Element e : elements) {
TypeElement providerImplementer = (TypeElement) e;
AnnotationMirror annotationMirror = getAnnotationMirror(e, AutoService.class).get();
Set<DeclaredType> providerInterfaces = getValueFieldOfClasses(annotationMirror);
if (providerInterfaces.isEmpty()) {
continue;
}
for (DeclaredType providerInterface : providerInterfaces) {
TypeElement providerType = MoreTypes.asTypeElement(providerInterface);
if (checkImplementer(providerImplementer, providerType)) {
providers.put(getBinaryName(providerType), getBinaryName(providerImplementer));
} else {
}
}
}
}
//創建配置文件
private void generateConfigFiles() {
Filer filer = processingEnv.getFiler();
for (String providerInterface : providers.keySet()) {
String resourceFile = "META-INF/services/" + providerInterface;
try {
SortedSet<String> allServices = Sets.newTreeSet();
try {
FileObject existingFile = filer.getResource(StandardLocation.CLASS_OUTPUT, "",
resourceFile);
Set<String> oldServices = ServicesFiles.readServiceFile(existingFile.openInputStream());
allServices.addAll(oldServices);
} catch (IOException e) {
}
Set<String> newServices = new HashSet<String>(providers.get(providerInterface));
if (allServices.containsAll(newServices)) {
return;
}
allServices.addAll(newServices);
FileObject fileObject = filer.createResource(StandardLocation.CLASS_OUTPUT, "",
resourceFile);
OutputStream out = fileObject.openOutputStream();
ServicesFiles.writeServiceFile(allServices, out);
out.close();
} catch (IOException e) {
fatalError("Unable to create " + resourceFile + ", " + e);
return;
}
}
}
}
AutoServoce工具和Lombok工具是類似的實現原理,通過java提供的注解處理器機制,在編譯期幫助我們創建一些文件或修改文件。