介绍

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


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

java中的SPI机制