java注解处理器之Google Auto Service
介绍
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提供的注解处理器机制,在编译期帮助我们创建一些文件或修改文件。