java注解的详细使用(APT、插桩、反射)

一、APT,编译时注解处理器

1、概述:

什么是apt:
APT,就是Annotation Processing Tool的简称,就是可以在代码编译期间对注解进行处理,并且生成Java文件,减少手动的代码输入。注解我们平时用到的比较多的可能会是运行时注解,比如大名鼎鼎的retrofit就是用运行时注解,通过动态代理来生成网络请求。编译时注解平时开发中可能会涉及的比较少,但并不是说不常用,比如我们经常用的轮子Dagger2, ButterKnife, EventBus3 都在用,所以要紧跟潮流来看看APT技术的来龙去脉。

编译时注解:
也有人叫它代码生成,其实他们还是有些区别的,在编译时对注解做处理,通过注解,获取必要信息,在项目中生成代码,运行时调用,和直接运行手写代码没有任何区别。而更准确的叫法:APT - Annotation Processing Tool

大概原理:
Java API 已经提供了扫描源码并解析注解的框架,开发者可以通过继承 AbstractProcessor 类来实现自己的注解解析逻辑。APT 的原理就是在注解了某些代码元素(如字段、函数、类等)后,在编译时编译器会检查 AbstractProcessor 的子类,并且自动调用其 process() 方法,然后将添加了指定注解的所有代码元素作为参数传递给该方法,开发者再根据注解元素在编译期输出对应的 Java 代码
APT在代码编译期解析注解,并且生成新的 Java 文件,减少手动的代码输入。

APT是一个命令行工具,它对源代码文件进行检测找出其中的annotation后,使用AbstractProcessor来处理annotation。

JavaPoet + Auto Service + java APT完成对编译时注解的处理。

2、Android studio中使用APT过程:

(1) 创建android过程SelfAnnotationProcessor
(2) 给工程添加java module:名称 apt: 主要用于处理运行时注解的解析工作;给工程添加java module:名称 anno: 主要用于定义运行时注解;
(3) 在app module的build.gradle添加依赖

annotationProcessorproject(":apt")
implementationproject(’:anno’)

在apt module的build.gradle添加依赖

Implementation project(‘:anno’)
implementation’com.squareup:javapoet:1.11.1’
implementation’com.google.auto.service:auto-service:1.0-rc2’

(4) 在 anno module下定义注解:
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD,ElementType.TYPE)
public @interface BindView {
   
    int value();
}
(5) 在app module的MainActivity中使用自定义注解 BindSelfView
@BindView(1)
public class MainActivity extends Activity{
   
    @BindView(R.id.textView1)
    TextView textView1;
    @BindView(R.id.textView2)
    TextView textView1;
    protected void onCreate(Bundle savedInstanceState){
   
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
    }
    @BindView(2)
    class ViewHolder{
   
    }
}
(6) 在apt module下定义自定义注解处理器(代码过长)
@AutoService(Processor.class)
@SupportedAnnotationTypes("com.example.sjh.anno.BindSelfView")
public class MyAnnoProcessor extends AbstractProcessor{
   

添加了 @AutoService(Processor.class)

那么就会在当前工程apt的META-INF下生成配置文件, 内容为注册的注解处理器
在这里插入图片描述
在init方法中进行工具类对象的获取:

@Override
public synchronized void init(ProcessingEnvironment processingEnvironment){
   
     System.out.printlin("MyAnnoProcessor init is invoke.processingEnvironment"+processingEnvironment);
     super.init(processingEnvironment);
     mFiler=processingEnvironment.getFiler();
     elementsUtils=processingEnvironment.getElementUtils();
}

在核心方法process里面对 被注解元素进行分析,并生成目标文件;

整个过程中用到TypeSpec,MethodSpec,JavaFile等对象

TypeSpec . Builder tb = TypeSpec . classBuilder( name: "MainActivity. _BindView" ).
            addModifiers (Modifier . PUBLIC, Modifier .FINAL)
            . addField(String.class, name: "textView", Modifier . PRIVATE)
            .addJavadoc(sb. tostring());
            
MethodSpec .Builder mb = MethodSpec . methodBuilder( name: "onCreate").returns(TypeName. VOID).
            addModifiers(Modifier.PUBLIC)
            .addParameter(String.class,"savedInstanceState");
Set<? extends Element> eleSet = roundEnvi ronment. getElementsAnnot at edWith(BindSeIfView.class);
Iterstorc? extends Element) t . eleSet.iterator();
while (it.haslext()) (
     Element ele=it.next();
     if(ele instanceof TypeElement) {
   
          Annotation anne=ele.getannotation(BindSelfView.class);
          BindSelfView view=(BindSelfView)anno;
          String desc="eleName:"+ele.getSimpleName().toString()+",annoNmae:"+anno.annotationType().getClass().getSimpleName()+",annoValue:"+view.value()+",kind:"+ele.getKind();
            
            CodeBlock cb=CodeBlock.builder()
               .addStatement(""+desc);
               .build();
            mb.addCode(cb);  
     }
}
tb.addMethod(mb.build());
JavaFile jf=JavaFile.builder
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值