注解原理
本文于 1290 天之前发表,文中内容可能已经过时。
[TOC]
注解
简析
元注解:修饰注解的注解,
- @Target:注解的作用目标(修饰方法,类还是字段)
- @Retention:注解的生命周期
- SOURCE:仅存在java源文件中,经过编译器后就丢弃,适用于一些检查行的操作,比如@Override
- CLASS:编译class文件时生效,适用于在编译时女性一些预处理操作,比如Butterknife的@BindView,在编译时,通过注解器生成一些辅助代码,完成完整的功能
- RUNTIME:保留在运行时VM中可以通过反射获取注解。适用于一些需要运行时动态获取注解信息,类似反射获取注解等,比如EventBus的@Subscribe
- @Documented:注解是否应当被包含在JavaDoc文档中
- @Inherited:是否允许子类继承该注解
- AnnotationInvocationHandler:专门处理注解的Handler
代码的生命周期包含:编码(SOURCE)—->编译(CLASS)—->运行(RUNTIME)
默认时注解在编译阶段,即CLASS阶段
本质:一个继承了Annotation接口的接口
- 运行时处理:使用反射获取当前的所需要的东西
- 编译时处理:APT技术,即编译期扫描java文件的注解,并传递到注解处理器,注解处理器可根据注解生成新的java文件
注解器
注解器通常是以Java代码(或者编译过的字节码)作为输入,生成.java文件作为输出
使用google的AutoService(@AutoService)可以自动生成resources/META-INF.services中的注册目录
包含注解处理器,注解声明库,实际使用APT的Android/Java项目
为什么把注解处理器独立抽成一个库呢?
对于Android项目默认是不包含 APT相关类的。所以要使用APT技术,那么就必须创建一个Java Library。对于Java项目,独立抽成一个库,更容易维护与扩展。
为什么把注解声明也单独抽成一个库,而不放到注解处理工具库中呢?
这样可以不用将注解处理器的相关代码大报道使用者的项目中去
注解器声明
其方法包含四个主要重写方法
- init() :初始化调用
- process():实际处理方法
- getSupportedAnnotationTypes():返回当前注解器处理注解的类型
- getSupportedSourceVersion():指定你使用的java版本
在注解处理过程中,会扫描所有的java源文件,查询注解,在java源代码中,每一部分都代表一个特定类型的Element,比如:
1 | package com.jennifer.andy.aptdemo.domain;//PackageElement |
注解处理器是运行在它自己的虚拟机JVM中,javac启动一个完整Java虚拟机来运行注解处理器。
最终是通过自定义注解器在编译时期生成加载注解后的类,在process方法中具体做了执行,编译了程序模版信息进行添加。
自定义注解
如果是单一属性,可以使用value字段
1 | MyAnno1 { |
如果不是value字段的话,需要(指定属性 = 值)
注解中只允许八中基本数据类型、字符串、类类型,注解类型,枚举类型及其一维数组