Java 注解的解析有两种方式:反射和注解处理器(APT/JSR 269),本文主要介绍注解处理器解析方式。  
 
解析方式 注解处理器解析注解的方式,是在编译期解析的,所以对注解的 Rentention 没有要求(即使 RetentionPolicy.SOURCE 也可以),可以根据编码需求自行设定。   
工具属性 注解处理器是 javac 的一个工具,它用来在编译时扫描和处理对应注解。一个注解的注解处理器,通常以 Java 代码(或者编译过的字节码)作为输入,生成文件(通常是 .java 文件)作为输出。这些生成的 Java 代码是在新生成的 .java 文件中,所以不能修改已经存在的 Java 类,例如向已有的类中添加方法。这些生成的 .java 文件,会同其他普通的手动编写的 Java 源代码一样被 javac 编译。   
独立进程 注解处理器是运行它自己的虚拟机 JVM 中的,javac 启动一个完整 Java 虚拟机来运行注解处理器,所以可以把注解处理器库看做一个独立的 Java 项目。   
 
自定义注解处理器流程 自定义注解和自定义注解处理器建议分成两个 jar 包,自定义注解处理器仅仅在编译期需要用到,所以工程中不需要将处理器打包到目标代码中。  
自定义注解库 Custom Annotation 在 AS 中新建 Java 库:File --> New --> New Module --> Java Libary ,新建 myanno 注解库。  
Gradle 文件:  
1 2 3 4 5 6 7 8 9 10 apply plugin: 'java-library'  dependencies  {    implementation fileTree (dir: 'libs' , include : ['*.jar' ]) } sourceCompatibility  = "1.8" targetCompatibility  = "1.8" 
 
注解源文件:  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Retention(RetentionPolicy.SOURCE) @Target(ElementType.FIELD) public  @interface  Field {    String value ()  ; } @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public  @interface  Info {    String author ()  ;     String date ()  ;     int  version ()  default  1 ;     String[] mails(); } @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) public  @interface  AnyAnnotation {    String value ()  ; } 
 
Gradle 中选择该库,编译生成对应的 jar: myanno。  
自定义注解处理器 Custom Processor 同样,需要新建一个自定义处理器 Java 库:processors。自定义注解处理器有两个步骤:  
自定义注解处理器必须继承 AbstractProcessor   
库的资源文件夹中添加 javax.annotation.processing.Processor 文件   
 
继承 AbstractProcessor 自定义注解处理器必须继承 AbstractProcessor ,使用 @SupportedAnnotationTypes 定义支持解析的注解,并重写 process 处理对应注解。  
1 2 3 4 5 6 7 8 9 10 @SupportedAnnotationTypes({"com.ymzs.annotation.Field"}) public  class  AnnotationParsingProcessor  extends  AbstractProcessor  {    @Override      public  boolean  process (Set<? extends TypeElement> set,           RoundEnvironment roundEnvironment)   {        System.out.println("AnnotationParsingProcessor::process" );         return  false ;     } } 
 
添加 javax.annotation.processing.Processor 文件 为了将自定义注解处理器注册到 javac 时,必须打包一个特殊的文件 javax.annotation.processing.Processor 到 META-INF/services 目录下。原因见 Java 技术手册 。  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // 源码目录结构 main     -java         -com             -ymzs                 -parsing                     -AnnotationParsingProcessor.java     -resources         -META-INF             -services                 -javax.annotation.processing.Processor // jar 包目录结构 processors.jar     -com         -ymzs             -parsing                 -AnnotationParsingProcessor.class     -META-INF         -services             -javax.annotation.processing.Processor         -MANIFEST.MF 
 
javax.annotation.processing.Processor 文件的内容是一个列表,每一行对应一个注解处理器的全称。例如:  
1 2 com.ymzs.parsing.AnnotationParsingProcessor com.ymzs.parsing.OtherProcessor 
 
Gradle 中选择该库,编译生成对应的 jar: processors。  
注解处理器插件 在 AS 中使用自定义注解处理器需要添加对应的 gradle 插件:  
1 2 3 4 5 6 7 8 9 10 11 12 13 plugins{     id 'java-library'           id "net.ltgt.apt"  version "0.15"  } dependencies {     ...          implementation project (":myanno" )            annotationProcessor project (":processors" )  } 
 
Android 环境Google 在发布 AS 时,开发了对应的 android-gradle-plugin,这是一系列插件包,并包含注解处理器插件:Android 注解处理器插件使用方法  。 使用该插件时,被注解代码工程的 gradle 文件中需要包含如下信息,关键词 annotationProcessor:   
 
1 2 3 4 5 6 7 8 9 10 11 apply plugin: 'com.android.application'  dependencies {     ...               implementation project (":myanno" )            annotationProcessor project (":processors" )  } 
 
结果验证 在 Gradle Projects 窗口中,选择需要被注解代码工程,选择 Tasks --> build --> assemble 编译工程,能正确的打印自定义注解处理器中的 Log :  
1 2 3 4 // 代码工程编译期,解析注解 :javabase:compileJava // 自定义注解处理器解析注解 AnnotationParsingProcessor::process 
 
APT 和 JSR269
APTAPT: Annotation-Processing Tool,相关 API 都在 com.sun.mirror 包下。从 Java 7 开始就被降级了,在 Java 8 被彻底移除,APT 移除原因  。   
JSR269JSR 269 API: Pluggable Annotation Processing API,相关 API 都在 javax.annotation.processing, javax.lang.model 包下。从 Java 6 开始引入,后续版本逐步代替了 APT。JSR 269    
 
不管是那种 API ,它们都是处理注解的工具,对源代码文件进行检测,并找出对应注解后解析(或生成对应文件)。通常用来简化开发者的工作量,或者生成附属文件。虽然 APT 被移除了,但是因为历史原因,注解处理器还是常用 APT 来称呼。本文都是基于 JSR 269 API 实现的自定义注解处理器。  
AnnotatedConstruct 体系类图结构 
AnnotatedConstruct 基本类AnnotatedConstruct JavaDoc   
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public  interface  AnnotatedConstruct   {         List<? extends AnnotationMirror> getAnnotationMirrors();          <A extends Annotation> A getAnnotation (Class<A> var1)  ;          <A extends Annotation> A[] getAnnotationsByType(Class<A> var1); } public  interface  AnnotationMirror   {         DeclaredType getAnnotationType ()  ;          Map<? extends ExecutableElement, ? extends AnnotationValue>          getElementValues(); } public  interface  AnnotationValue   {         Object getValue ()  ;     String toString ()  ;     <R, P> R accept (AnnotationValueVisitor<R, P> var1, P var2)  ; } 
 
TypeMirror 体系TypeMirror JavaDoc   
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 public  enum  TypeKind   {         BOOLEAN,     BYTE,     SHORT,     INT,     LONG,     CHAR,     FLOAT,     DOUBLE,     VOID,     NONE,     NULL,     ARRAY,          DECLARED,          ERROR,          TYPEVAR,     WILDCARD,     PACKAGE,          EXECUTABLE,     OTHER,     UNION,     INTERSECTION;     private  TypeKind ()   {     }     public  boolean  isPrimitive ()   {         switch (this ) {         case  BOOLEAN:         case  BYTE:         case  SHORT:         case  INT:         case  LONG:         case  CHAR:         case  FLOAT:         case  DOUBLE:             return  true ;         default :             return  false ;         }     } } public  interface  TypeMirror  extends  AnnotatedConstruct   {         TypeKind getKind ()  ;     boolean  equals (Object var1)  ;     int  hashCode ()  ;     String toString ()  ;     <R, P> R accept (TypeVisitor<R, P> var1, P var2)  ; } public  interface  IntersectionType  extends  TypeMirror   {         List<? extends TypeMirror> getBounds(); } public  interface  UnionType  extends  TypeMirror   {         List<? extends TypeMirror> getAlternatives(); } public  interface  ExecutableType  extends  TypeMirror   {         List<? extends TypeVariable> getTypeVariables();          TypeMirror getReturnType ()  ;          List<? extends TypeMirror> getParameterTypes();          TypeMirror getReceiverType ()  ;          List<? extends TypeMirror> getThrownTypes(); } public  interface  NoType  extends  TypeMirror   {}public  interface  PrimitiveType  extends  TypeMirror   {}public  interface  WildcardType  extends  TypeMirror   {         TypeMirror getExtendsBound ()  ;          TypeMirror getSuperBound ()  ; } public  interface  ReferenceType  extends  TypeMirror   {}public  interface  ArrayType  extends  ReferenceType   {         TypeMirror getComponentType ()  ; } public  interface  NullType  extends  ReferenceType   {}public  interface  TypeVariable  extends  ReferenceType   {         Element asElement ()  ;     TypeMirror getUpperBound ()  ;     TypeMirror getLowerBound ()  ; } public  interface  DeclaredType  extends  ReferenceType   {         Element asElement ()  ;          TypeMirror getEnclosingType ()  ;          List<? extends TypeMirror> getTypeArguments(); } public  interface  ErrorType  extends  DeclaredType   {}
 
Element 体系Element JavaDoc   
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 public  enum  ElementKind   {    PACKAGE,     ENUM,     CLASS,     ANNOTATION_TYPE,     INTERFACE,     ENUM_CONSTANT,     FIELD,     PARAMETER,     LOCAL_VARIABLE,     EXCEPTION_PARAMETER,     METHOD,     CONSTRUCTOR,     STATIC_INIT,     INSTANCE_INIT,     TYPE_PARAMETER,     OTHER,     RESOURCE_VARIABLE;     private  ElementKind ()   {     }     public  boolean  isClass ()   {         return  this  == CLASS || this  == ENUM;     }     public  boolean  isInterface ()   {         return  this  == INTERFACE || this  == ANNOTATION_TYPE;     }     public  boolean  isField ()   {         return  this  == FIELD || this  == ENUM_CONSTANT;     } } public  enum  Modifier   {    PUBLIC,     PROTECTED,     PRIVATE,     ABSTRACT,     DEFAULT,     STATIC,     FINAL,     TRANSIENT,     VOLATILE,     SYNCHRONIZED,     NATIVE,     STRICTFP;     private  Modifier ()   {     }     public  String toString ()   {         return  this .name().toLowerCase(Locale.US);     } } public  enum  NestingKind   {    TOP_LEVEL,     MEMBER,     LOCAL,     ANONYMOUS;     private  NestingKind ()   {     }     public  boolean  isNested ()   {         return  this  != TOP_LEVEL;     } } public  interface  Element  extends  AnnotatedConstruct   {         TypeMirror asType ()  ;          ElementKind getKind ()  ;          Set<Modifier> getModifiers ()  ;          Name getSimpleName ()  ;          Element getEnclosingElement ()  ;               List<? extends Element> getEnclosedElements();     boolean  equals (Object var1)  ;     int  hashCode ()  ;          List<? extends AnnotationMirror> getAnnotationMirrors();          <A extends Annotation> A getAnnotation (Class<A> var1)  ;          <R, P> R accept (ElementVisitor<R, P> var1, P var2)  ; } public  interface  QualifiedNameable  extends  Element   {         Name getQualifiedName ()  ; } public  interface  PackageElement  extends  Element , QualifiedNameable   {    Name getQualifiedName ()  ;     Name getSimpleName ()  ;         List<? extends Element> getEnclosedElements();          boolean  isUnnamed ()  ;     Element getEnclosingElement ()  ; } public  interface  VariableElement  extends  Element   {         Object getConstantValue ()  ;     Name getSimpleName ()  ;     Element getEnclosingElement ()  ; } public  interface  TypeParameterElement  extends  Element   {         Element getGenericElement ()  ;          List<? extends TypeMirror> getBounds();     Element getEnclosingElement ()  ; } public  interface  Parameterizable  extends  Element   {         List<? extends TypeParameterElement> getTypeParameters(); } public  interface  ExecutableElement  extends  Element , Parameterizable   {    List<? extends TypeParameterElement> getTypeParameters();          TypeMirror getReturnType ()  ;          List<? extends VariableElement> getParameters();          TypeMirror getReceiverType ()  ;          boolean  isVarArgs ()  ;          boolean  isDefault ()  ;          List<? extends TypeMirror> getThrownTypes();          AnnotationValue getDefaultValue ()  ;     Name getSimpleName ()  ; } public  interface  TypeElement  extends  Element , Parameterizable ,     QualifiedNameable   {    List<? extends Element> getEnclosedElements();          NestingKind getNestingKind ()  ;     Name getQualifiedName ()  ;     Name getSimpleName ()  ;          TypeMirror getSuperclass ()  ;          List<? extends TypeMirror> getInterfaces();     List<? extends TypeParameterElement> getTypeParameters();     Element getEnclosingElement ()  ; } 
 
源代码的每一个部分都是一个特定类型的 Element,也就是说 Element 代表程序的任意元素,例如包、类、方法等。每个 Element 代表一个静态的、语言级别的构件。  
1 2 3 4 5 6 7 8 9 10 package  com.example;        public  class  Foo   {          private  int  a;           private  Foo other;       public  Foo  ()   {}         public  void  setA  (  // ExecuteableElement          int  newA        // TypeElement     )   {}} 
 
换个角度来看源代码,它只是结构化的文本,不是可运行的。可以想象它就像要被解析的 XML 文件一样(或者是编译器中抽象的语法树)。就像 XML 解释器一样,有一些类似 DOM 的元素,可以从一个元素导航到它的父或者子元素上。 举例来说,假如有一个代表 public class Foo 类的 TypeElement 元素,可以遍历它的所有元素:  
1 2 3 4 TypeElement fooClass = ... ;   for  (Element e : fooClass.getEnclosedElements()){      Element parent = e.getEnclosingElement();       } 
 
Elements 接口用来处理 Element 的工具类,Elements JavaDoc  。  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public  interface  Elements   {         PackageElement getPackageElement (CharSequence name)  ;          TypeElement getTypeElement (CharSequence name)  ;          Map<? extends ExecutableElement, ? extends AnnotationValue>          getElementValuesWithDefaults(AnnotationMirror var1);          String getDocComment (Element var1)  ;     boolean  isDeprecated (Element var1)  ;          Name getBinaryName (TypeElement var1)  ;          PackageElement getPackageOf (Element var1)  ;          List<? extends Element> getAllMembers(TypeElement var1);          List<? extends AnnotationMirror> getAllAnnotationMirrors(Element var1);          boolean  hides (Element hider, Element hidden)  ;          boolean  overrides (ExecutableElement overrider,           ExecutableElement overridden, TypeElement type)  ;         String getConstantExpression (Object var1)  ;     void  printElements (Writer var1, Element... var2)  ;     Name getName (CharSequence var1)  ;     boolean  isFunctionalInterface (TypeElement var1)  ; } 
 
Types 接口用来处理 TypeMirror 的工具类,Types JavaDoc  。  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public  interface  Types   {         Element asElement (TypeMirror var1)  ;     boolean  isSameType (TypeMirror var1, TypeMirror var2)  ;     boolean  isSubtype (TypeMirror var1, TypeMirror var2)  ;          boolean  isAssignable (TypeMirror var1, TypeMirror var2)  ;     boolean  contains (TypeMirror var1, TypeMirror var2)  ;          boolean  isSubsignature (ExecutableType var1, ExecutableType var2)  ;          List<? extends TypeMirror> directSupertypes(TypeMirror var1);          TypeMirror erasure (TypeMirror var1)  ;          TypeElement boxedClass (PrimitiveType var1)  ;          PrimitiveType unboxedType (TypeMirror var1)  ;          TypeMirror capture (TypeMirror var1)  ;     PrimitiveType getPrimitiveType (TypeKind var1)  ;     NullType getNullType ()  ;     NoType getNoType (TypeKind var1)  ;     ArrayType getArrayType (TypeMirror var1)  ;          WildcardType getWildcardType (TypeMirror extendsBound,            TypeMirror superBound)  ;         DeclaredType getDeclaredType (TypeElement typeElem,            TypeMirror... typeArgs)  ;         DeclaredType getDeclaredType (DeclaredType containing,            TypeElement typeElem, TypeMirror... typeArgs)  ;         TypeMirror asMemberOf (DeclaredType containing, Element element)  ; } 
 
Filer 接口用来创建文件,Filer JavaDoc  。  
1 2 3 4 5 6 7 8 9 10 public  interface  Filer   {    JavaFileObject createSourceFile (CharSequence var1, Element... var2)            throws  IOException ;    JavaFileObject createClassFile (CharSequence var1, Element... var2)            throws  IOException ;    FileObject createResource (Location var1, CharSequence var2,            CharSequence var3, Element... var4)  throws  IOException ;    FileObject getResource (Location var1, CharSequence var2,            CharSequence var3)  throws  IOException ;} 
 
Messager 接口提供给注解处理器一个报告错误、警告以及提示信息的途径。Messager JavaDoc  , 消息级别 Diagnostic.Kind  。 因为注解处理器是在独立的 java 虚拟机运行,所以注解处理器中不能直接进行异常抛出,否则进程异常崩溃时,会弹出一大堆让人捉摸不清的堆栈调用日志显示,也就是目标工程报的错误来自于另外一个虚拟机的堆栈。通常使用 Messager 来写一些信息给使用此注解器的第三方开发者的。在官方文档中描述了消息的不同级别,非常重要的是 Kind.ERROR,因为这种类型的信息用来表示我们的注解处理器处理失败了,很有可能是第三方开发者错误的使用了注解。 
1 2 3 4 5 6 7 8 9 public  interface  Messager   {    void  printMessage (Kind var1, CharSequence var2)  ;     void  printMessage (Kind var1, CharSequence var2, Element var3)  ;     void  printMessage (Kind var1, CharSequence var2, Element var3,           AnnotationMirror var4)  ;    void  printMessage (Kind var1, CharSequence var2, Element var3,           AnnotationMirror var4, AnnotationValue var5)  ;} 
 
AbstractProcessor 详细分析自定义处理器通常会继承 AbstractProcessor,并重写对应方法,来实现自定义注解的解析。所有的注解处理器类都必须有一个无参构造函数 ,否则执行时会报错。 对应源码文件目录:src\javax\annotation\processing  
类图结构 
常用 API 介绍 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public  interface  Processor   {    Set<String> getSupportedOptions ()  ;                    Set<String> getSupportedAnnotationTypes ()  ;               SourceVersion getSupportedSourceVersion ()  ;          void  init (ProcessingEnvironment processingEnv)  ;          boolean  process (Set<? extends TypeElement> annotations,          RoundEnvironment roundEnv)  ;         Iterable<? extends Completion> getCompletions(Element element,         AnnotationMirror annotation, ExecutableElement member,         String userText); } public  abstract  class  AbstractProcessor  implements  Processor   {    ...     public  abstract  boolean  process (Set<? extends TypeElement> annotations,                                      RoundEnvironment roundEnv)  ;    ... } 
 
两个有用的注解 
循环调用 process process 通常会被执行两次:根据 Log 可以发现,process 的返回值不管是 true/false 都会被执行两次?但是解析注解时,只有第一次执行 process 时,roundEnvironment.getElementsAnnotatedWith 才能获取到注解。 具体原因参考 Processor JavaDoc  。官方文档中第一段就介绍了,注解处理器是个循环处理的过程,每次循环都会解析上次处理器产生的源文件。也就是说第一次 process 处理了编写的源文件,第二次处理了注解处理器生成的源文件(此时已经不包含被处理的注解了),直到所有支持的注解都被解析完毕。  
存在的问题 不管是使用 @SupportedAnnotationTypes 还是重写 getSupportedAnnotationTypes() ,只要支持注解包其中一个注解,注解处理器就能解析该包中的所有其他注解。  
1 2 3 4 // Java library: myanno @Info @Field @AnyAnnotation 
 
注解包 myanno 包含三个注解,但是在自定义注解器中,代码中规定只支持 Field 注解,自定义注解器仍然能解析 Info, AnyAnnotation ?  
注解处理器插件 
gradle-apt-plugin Java 环境下注解插件,使用方法:  1 2 3 4 5 6 7 8 9 plugins{     id "net.ltgt.apt"  version "0.15"  } dependencies {          annotationProcessor project (":processors" )            annotationProcessor "com.custom:CustomProcessors:version1.2.3"   } 
 
android-apt Android 注解器框架,现在已经不再维护。   
annotationProcessorAndroid Plugin for Gradle,google 为 gradle 开发的注解处理器框架,用于替换 android-apt。使用方法:  1 2 3 4 annotationProcessor ":customProcessors"  annotationProcessor "com.custom:CustomProcessors:version1.2.3"    
 
 
 
常用开源库 
AutoService 官网  自动生成 javax.annotation.processing.Processor 文件,并将自定义注解处理器按照规范加入该文件。   
JavaPoet 官网  生成 .java 源文件的 API 接口,非常强大实用。解析自定义注解时,可以使用 JavaPoet 来生成对应文件。   
 
AutoService 用法
build.gradle 文件中添加依赖implementation 'com.google.auto.service:auto-service:1.0-rc4' 具体版本号,到 github 官网上查看。   
自定义注解处理器类上添加 AutoService 注解 在自定义处理器类上,添加 @AutoService(Processor.class) 注解。该注解会自动生成对应的 META-INF/services/javax.annotation.processing.Processor 文件,并将自定义注解处理器按照规范加入该文件。   
 
JavaPoet 用法 
其他 调试注解处理器 
常用场景 大量开源库都使用了注解处理器简化代码:  
参考文档