0
点赞
收藏
分享

微信扫一扫

java - 注解解析与自定义

黎轩的闲暇时光 2022-04-01 阅读 61
java

一.Annotation

注解的基本结构就是一个@加字符,可以放在需要修饰的类、方法、变量和参数等元素前面。

Annotation并不直接影响代码的语义,但是他可以被看做是程序的工具或者类库。它会反过来对正在运行的程序语义有所影响。

Annotation可以从源文件、class文件或者在运行时通过反射机制多种方式被读取。

Java中有五个元注解 (即作用在其它注解的标准注解)@Retention@Documented@Target@Inherited@Repeatable

  • @Retention:决定这个注解的存活时间;(这里注意下!!)

  • @Documented:被该注解修饰的类可以被javadoc工具提取成文档;

  • @Target:表明该注解可以修饰哪些元素;

  • @Inherited:被该注解修饰的注解有继承性;

  • @Repeatable:表明该注解可以多次应用修饰同一个元素。

这里重点了解下@Target和@Retention设置的值:

1.@Target

// @Target使用ElementType值
public enum ElementType {
    TYPE,               // 类、接口(包括注解类型)或枚举声明
    FIELD,              // 变量声明(包括枚举常量)
    METHOD,             // 方法声明
    PARAMETER,          // 参数声明
    CONSTRUCTOR,        // 构造方法声明
    LOCAL_VARIABLE,     // 局部变量声明
    ANNOTATION_TYPE,    // 注解类型声明
    PACKAGE             // 包声明
}

2.@Retention

// @Retention使用RetentionPolicy值
public enum RetentionPolicy {
    SOURCE,             // 指定注解信息只保留在源码中,编译后注解信息消失,并不会保存在.class文件中。
    CLASS,              // 编译后注解信息存储于对应的.class文件中,但执行时并不会加载到JVM中。(没有指定时默认为CLASS)  
    RUNTIME             // 与CLASS不同的是,执行时注解信息会加入到JVM中。(通过class对象getAnnotation获取到)
}

3.自定义注解

使用@interface来自定义注解:public @interface 注解名 {定义体}

// 自定义注解写法

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
    public int value() default 0;
    // Annotation添加变量:
    // 1. 只能用public或默认(default)这两个访问权修饰。
    // 2. 参数成员只能用基本类型和String, Enum, Class等数据类型,以及这一些类型的数组。
    // 3. 如果只有一个属性,建议使用"value",后加小括号。在使用时直接括号里放值,其它情况name=value。
    // 4. 使用default指定默认值。
}

调用:

@Test(100)
public class Main {

    public static void main(String[] args) {

        Class<?> clz = Main.class;
        Test annotation = clz.getAnnotation(Test.class);
        int value = annotation.value();
        System.out.println("value=" + value);

    }


}

二.APT技术

1.注解处理器

APT(Annotation Processing Tool)即注解处理器,一种处理注解的工具 (在Javac中)

简单来说就是编译时期,对源代码文件进行检测并找出其中的Annotation,按照一定规则生成相应的java文件。

JVM能处理自带的注解,而自定义的注解则需要实现自己的注解处理器来处理 (extends AbstractProcessor)

/**
 * 在这个类上添加了@AutoService注解,它的作用是用来生成
 * META-INF/services/javax.annotation.processing.Processor文件的,
 * 也就是我们在使用注解处理器的时候需要手动添加
 * META-INF/services/javax.annotation.processing.Processor,
 * 而有了@AutoService后它会自动帮我们生成。
 * AutoService是Google开发的一个库,使用时需要添加依赖。
 */
@AutoService(Processor.class)
public class CustomProcessor extends AbstractProcessor {
  
  // 处理节点的工具类(类、函数、属性都是节点)
  private Elements elementUtils;
    
  // 处理类信息(TypeMirror)工具类
  private Types typeUtils;
    
  // 文件相关的辅助类:用于生成新的源文件、class等
  private Filer filer;

  // 主要做一些初始化操作
  @Override
  public synchronized void init(ProcessingEnvironment env){ 
     elementUtils = env.getElementUtils();
     typeUtils = env.getTypeUtils();
     filer = env.getFiler();
  }
 
  /**
   * 具体处理注解的逻辑,控制代码的生成
   *
   * @param annoations        使用了支持处理注解  的节点集合
   * @param roundEnvironment  表示当前或是之前的运行环境,可以通过该对象查找找到的注解。
   * @return true             表示后续处理器不会再处理 (已经处理)
   */
  @Override
  public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { 
    return false;
  }

  // 支持处理的注解类型,也可以通过@SupportedAnnotationTypes来指定
  @Override
  public Set<String> getSupportedAnnotationTypes() { 
    return super.getSupportedAnnotationTypes();
  }

  // 指定使用的Java版本,也可以通过@SupportedSourceVersion设定
  @Override
  public SourceVersion getSupportedSourceVersion() {
    return super.getSupportedSourceVersion();
  }
    
  // 处理器接收的参数(指定key),可以使用@SupportedOptions来设定
  // 在build.gradle中可以添加arguments:
  // javaCompileOptions {
  //   annotationProcessorOptions {
  //     arguments = ["argumentKey": value]
  //   }
  // }
  // 在ProcessingEnvironment通过getOptions()获取到对应的Map
  @Override
  public Set<String> getSupportedOptions() {
    return super.getSupportedOptions();
  }
  
}

这里用到了AutoService需要在build.gradle中导入library:

annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'

主要使用如下:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dog {

    String value() default "dog";
}
@AutoService(Processor.class)
@SupportedAnnotationTypes("com.dn.lib_annotation.Dog")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class DogProcessor extends AbstractProcessor {

    Messager messager;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        messager = processingEnvironment.getMessager();
        messager.printMessage(Diagnostic.Kind.NOTE, "init..");

//        processingEnvironment.getElementUtils();
//        processingEnvironment.getFiler();
//        processingEnvironment.getTypeUtils();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        messager.printMessage(Diagnostic.Kind.NOTE, "process..");


        // 获取所有的被指定的注解作用的元素集合
        Set<? extends Element> dogElements = roundEnvironment.getElementsAnnotatedWith(Dog.class);
        for (Element element : dogElements) {
            messager.printMessage(Diagnostic.Kind.NOTE, element.getKind().name());
        }

        return false;
    }

//    @Override
//    public Set<String> getSupportedAnnotationTypes() {
//        return super.getSupportedAnnotationTypes();
//    }
//
//    @Override
//    public SourceVersion getSupportedSourceVersion() {
//        return super.getSupportedSourceVersion();
//    }

}

public class Main {

    @Dog("dahei")
    private String animal = "xiaohei";

    public static void main(String[] args) {

    }

}

具体打印信息会在bulid里打印出来。

举报

相关推荐

0 条评论