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

posted @ 2020-07-11 17:31  strongmore  阅读(7451)  评论(0编辑  收藏  举报