[转]java注解与APT技术

 

下面是一个简单的自定义注解的栗子:

package annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**

  • 动物名称注解

*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AnimalName {
String value() default "";
}

 

定义了注解,并在需要的时候给相关类,类属性加上注解信息,如果没有响应的注解信息处理流程,注解可以说是没有实用价值,接下来要介绍的是 java 的 APT(Annotation Process Tool) 技术,用于处理自定义注解。

2,APT 技术

APT(Annotation Process Tool),是一种在代码编译时处理注解,按照一定的规则,生成相应的 java 文件,多用于对自定义注解的处理,目前比较流行的 Dagger2, ButterKnife, EventBus3 都是采用 APT 技术,对运行时的性能影响很小。我们通过自定义注解的方式,来了解一下如何使用 APT:

1,自定义注解:

@Target({ElementType.TYPE})   ---作用范围 Class

@Retention(RetentionPolicy.CLASS) --- 生命周期:仅保留到.class 文件

public @interface Route {
/** Path of route*/
String value(); ---类似于成员变量
}

 

2,使用方式

@Route(path = "/test/activity2")
public class MainActivity extends AppCompatActivity {
<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">onCreate</span><span class="hljs-params">(Bundle savedInstanceState)</span> {
    <span class="hljs-built_in">super</span>.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test2);
}

}

JVM 默认只会处理 @override 等语言自带的注解,对于自定义的注解,需要我们自己处理,java 提供了一个名为 AbstractProcessor.java 的抽象类,我们只要继承该类,就实现自己的注解处理器,来处理自定义的 @Route 注解

public class RouteProcessor extends AbstractProcessor {
<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">init</span><span class="hljs-params">(ProcessingEnvironment env)</span>{ 
    <span class="hljs-comment">// 主要做一些初始化操作</span>
}

<span class="hljs-meta">@Override</span>
    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">process</span><span class="hljs-params">(Set&lt;? extends TypeElement&gt; annoations, RoundEnvironment env)</span> { 
    <span class="hljs-comment">//具体处理注解的逻辑,控制代码的生成</span>
    processAnnotations();
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> Set&lt;String&gt; <span class="hljs-title function_">getSupportedAnnotationTypes</span><span class="hljs-params">()</span> { 
   <span class="hljs-comment">// 支持处理的注解类型, 在这里就是@Route</span>

}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> SourceVersion <span class="hljs-title function_">getSupportedSourceVersion</span><span class="hljs-params">()</span> {
  <span class="hljs-comment">//java版本 如:jdk1.6or jdk1.7</span>

}

}


3,自定义 Processor

@AutoService(Processor.class)
public class HelloProcessor extends AbstractProcessor {
<span class="hljs-comment">/** 文件相关的辅助类 用于生成新的源文件、class等 */</span>
<span class="hljs-keyword">private</span> Filer mFiler;

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">init</span><span class="hljs-params">(ProcessingEnvironment processingEnv)</span> {
    <span class="hljs-built_in">super</span>.init(processingEnv);
    mFiler = processingEnv.getFiler();
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">process</span><span class="hljs-params">(Set&lt;? extends TypeElement&gt; annotations, RoundEnvironment roundEnv)</span> {

    <span class="hljs-comment">// 构建方法 此处使用到了square公司的javapoet库,用来辅助生成 类的代码</span>
    MethodSpec.<span class="hljs-type">Builder</span> <span class="hljs-variable">methodBuilder</span> <span class="hljs-operator">=</span> MethodSpec.methodBuilder(<span class="hljs-string">"show"</span>)
            .addModifiers(Modifier.PUBLIC);
    methodBuilder.addStatement(<span class="hljs-string">"String test = \"$N\" "</span>,<span class="hljs-string">"hello annotation world!"</span>);

    <span class="hljs-comment">/** 构建类 */</span>
    <span class="hljs-type">TypeSpec</span> <span class="hljs-variable">finderClass</span> <span class="hljs-operator">=</span> TypeSpec.classBuilder(<span class="hljs-string">"Hello$$Inject"</span>)
            .addModifiers(Modifier.PUBLIC)
            .addMethod(methodBuilder.build())
            .build();
    <span class="hljs-keyword">try</span> {
        JavaFile.builder(<span class="hljs-string">"com.win.test"</span>,finderClass).build().writeTo(mFiler);
    } <span class="hljs-keyword">catch</span> (IOException e) {
        e.printStackTrace();
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}

<span class="hljs-comment">// 支持的注解类型</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> Set&lt;String&gt; <span class="hljs-title function_">getSupportedAnnotationTypes</span><span class="hljs-params">()</span> {
    Set&lt;String&gt; types = <span class="hljs-keyword">new</span> <span class="hljs-title class_">LinkedHashSet</span>&lt;&gt;();
    types.add(Hello.class.getCanonicalName());
    <span class="hljs-keyword">return</span> types;
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> SourceVersion <span class="hljs-title function_">getSupportedSourceVersion</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">super</span>.getSupportedSourceVersion();
}

}

在 AS 工程中使用

@Hello("MainTest")   // 自定义的 Hello 注解
public class MainActivity extends AppCompatActivity {
<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">onCreate</span><span class="hljs-params">(Bundle savedInstanceState)</span> {
    <span class="hljs-built_in">super</span>.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

}

在项目 App module 的 build 目录下,便会生成对应的 java 类文件:

这里写图片描述

这个只是简单的栗子,我们可以在 process() 方法中,加入更多的业务逻辑,以实现特定功能。