一.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里打印出来。