[转]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 {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test2);
    }
}

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

public class RouteProcessor extends AbstractProcessor {

    @Override
    public synchronized void init(ProcessingEnvironment env){ 
        // 主要做一些初始化操作
    }

    @Override
        public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { 
        //具体处理注解的逻辑,控制代码的生成
        processAnnotations();
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() { 
       // 支持处理的注解类型, 在这里就是@Route

    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
      //java版本 如:jdk1.6or jdk1.7
   }

}

3,自定义Processor

@AutoService(Processor.class)
public class HelloProcessor extends AbstractProcessor {

    /** 文件相关的辅助类 用于生成新的源文件、class等 */
    private Filer mFiler;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        mFiler = processingEnv.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

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

        /** 构建类 */
        TypeSpec finderClass = TypeSpec.classBuilder("Hello$$Inject")
                .addModifiers(Modifier.PUBLIC)
                .addMethod(methodBuilder.build())
                .build();
        try {
            JavaFile.builder("com.win.test",finderClass).build().writeTo(mFiler);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    // 支持的注解类型
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>();
        types.add(Hello.class.getCanonicalName());
        return types;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return super.getSupportedSourceVersion();
    }
}

在AS工程中使用

@Hello("MainTest")   //自定义的Hello注解
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

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

这里写图片描述

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

posted on 2018-05-31 02:45  曲进笑谈  阅读(2790)  评论(0编辑  收藏  举报