深入拆解 Java 虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
87446 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 40 讲
模块四:黑科技 (3讲)
深入拆解 Java 虚拟机
15
15
1.0x
00:00/00:00
登录|注册

27 | 注解处理器

触发新一轮的编译
生成新的源文件
检查是否有相应的getter方法
遍历被标注的类中的实例字段
实现process方法
@SupportedSourceVersion
@SupportedAnnotationTypes
process
getSupportedSourceVersion
getSupportedAnnotationTypes
init
生成字节码
调用已注册的注解处理器
Java编译器的工作流程
仅对Java编译器有用
限定当前注解生命周期
限定目标注解所能标注的Java结构
Java源代码的编译过程
注解处理器的三个用途
Adapt注解处理器
生成源代码的方式
读取注解中的值
CheckGetter注解处理器
抽象类AbstractProcessor
接口Processor
原理
用于修改已有的Java源文件或生成新的Java源文件
例子:@Override注解
为类、方法、字段、参数等Java结构提供额外信息的机制
总结与实践
利用注解处理器生成源代码
注解处理器
注解(annotation)
注解处理器

该思维导图由 AI 生成,仅供参考

注解(annotation)是 Java 5 引入的,用来为类、方法、字段、参数等 Java 结构提供额外信息的机制。我先举个例子,比如,Java 核心类库中的@Override注解是被用来声明某个实例方法重写了父类的同名同参数类型的方法。
package java.lang;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Override注解本身被另外两个元注解(即作用在注解上的注解)所标注。其中,@Target用来限定目标注解所能标注的 Java 结构,这里@Override便只能被用来标注方法。
@Retention则用来限定当前注解生命周期。注解共有三种不同的生命周期:SOURCECLASSRUNTIME,分别表示注解只出现在源代码中,只出现在源代码和字节码中,以及出现在源代码、字节码和运行过程中。
这里@Override便只能出现在源代码中。一旦标注了@Override的方法所在的源代码被编译为字节码,该注解便会被擦除。
我们不难猜到,@Override仅对 Java 编译器有用。事实上,它会为 Java 编译器引入了一条新的编译规则,即如果所标注的方法不是 Java 语言中的重写方法,那么编译器会报错。而当编译完成时,它的使命也就结束了。
我们知道,Java 的注解机制允许开发人员自定义注解。这些自定义注解同样可以为 Java 编译器添加编译规则。不过,这种功能需要由开发人员提供,并且以插件的形式接入 Java 编译器中,这些插件我们称之为注解处理器(annotation processor)。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了Java编译器的注解处理器,重点讨论了注解处理器的定义、使用和原理。通过案例详细阐述了注解处理器的功能和原理,以及如何注册和使用注解处理器。文章内容涉及注解的定义、注解处理器的实现和注册,适合开发人员了解注解处理器的基本概念和使用方法。注解处理器主要有三个用途:定义编译规则并检查源文件、修改已有源代码以及生成新的源代码。其中,生成新的源代码是较为常见的用途,例如OpenJDK工具jcstress和JMH生成测试代码的方式。文章还介绍了Java源代码的编译过程,包括解析源文件生成抽象语法树、调用已注册的注解处理器和生成字节码。如果在调用注解处理器的过程中生成了新的源代码,Java编译器将重复前两个步骤,直至不再生成新的源代码。文章提供了一个实践环节,鼓励读者实现案例中的TODO项,处理由`@CheckGetter`注解的字段。整体而言,本文为开发人员提供了深入了解和使用Java编译器的注解处理器的指导和实践。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入拆解 Java 虚拟机》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(19)

  • 最新
  • 精选
  • 聚变
    编译时生成与 运行时使用cglib等类库生成的字节码,在性能和使用场景上有什么区别吗??

    作者回复: Cglib等字节码工具会影响启动性能,峰值性能上没啥区别。 如果对字节码不熟的话,用注解处理器比较容易些。另一方面,字节码处理工具更强大些,能做很多源代码不能做的。

    2018-09-21
    18
  • 嗯,之前写过注解方面的功能,不过虽然能自定义注解,也能明白Java语言层面的有关注解相关的知识点,但是往下怎么样就不太清楚了? 注解代码本质也是代码,也会被编译为.class文件,然后在JVM上面被转换成机器码,然后被计算机执行,不过感觉他好特别,他的存在仅是为了是编码更简洁吗? 读之前我就在想上面的问题,文中虽然没有介绍这些内容,不过介绍了其他的内容也挺好! 小结一下: 1:注解处理器-本质也是代码,以插件的形式存在,以插件的形式接入Java编译器,这些插件有什么用呢? 2:注解处理器的作用? 注解处理器有三个作用 2-1:可以为Java编译器添加一些编译规则,这也就是传说中的自定义注解,它可以定义一些编译规则,这些编译规则会以插件的形式提供给Java编译器。 2-2:可以修改已有的JAVA源文件(不推荐,为什么呢?因为本质上注解处理器不能修改已有的JAVA源代码,但是它可以修改有java源代码生成的抽象语法树,从而使生成的字节码发生变化,不过对抽象语法树的修改修改设计了java编译器的内部API,这部分很可能随着版本的变更而失效,所以,才不推荐使用的,存在埋深坑的隐患。) 2-3:可以生成一些新的JAVA源文件 3:元注解-给注解使用的注解就是元注解,这些注解是JDK的开发人员提前定义了的,也同样是以插件的形式接入Java编译器的。注意:所有的注解处理器都必须实现Processor接口,这个接口中有四个方法,每个方法都有其特殊的作用在,详情需要回头细看。另外,JDK提供了一个实现Processor接口的抽象类AbstractProcessor,这个抽象类实现了Processor接口的其中三个方法。 4:自定义的注解被编译为.class文件后,便可以将其注册为Java编译器的插件了,注册方法有两种,祥看专栏内容吧! 5:Java源代码的编译过程分为三个步骤 5-1:解析源文件生成抽象语法树 5-2:调用已注册的注解处理器(注解处理器有两种注册到JAVA编译器的方式) 5-3:生成字节码 5-4:如果5-2步中,注解处理器生成了新的源代码,那么JAVA编译器将重复第5-1/5-2步,直到不再生成新的源代码。

    作者回复: 注解相当于给某些代码贴了个标签。我们既可以通过注解处理器在编译时解析这些标签,也可以在运行时通过反射解析这些标签。解析后都会有一系列动作,这些动作就是对标签语义的诠释。

    2018-09-24
    16
  • 补心
    Lombok随着Java版本的问题,是不是有可能没法使用。

    作者回复: 有可能,因为用的是internal API。

    2018-09-21
    7
  • 松花皮蛋me
    反射在运行时,注解解释器在编译时
    2019-03-16
    7
  • lovedebug
    讲的很好,赞。结合java语法看印象更深
    2018-09-27
    7
  • 白三岁
    spring中的那些注解也是通过注解处理器实现的吗。我们项目中一般好像都是通过spring的aop来实现自定义注解的功能。
    2018-09-28
    1
    4
  • 小陈
    这个比深入理解jvm那部分详细
    2020-03-29
    2
  • 蚂蚁内推+v
    郑老师 有个问题我一直想不明白?java 源码生成语法树 java APT 处理器处理后生成代码, 从新走那个过程 有重复生成了 那不是死循环了吗?可能是自己知识浅薄 麻烦在这点上正老师能指点下☺️ 自己水平比较low 模仿了写一直没成功☺️ 不知道郑老师能发一个demo 工程吗
    2018-09-23
    1
    2
  • hresh
    深入源码分析注解处理器是如何工作的,带你手撸@Getter注解,让你体会一下Lombok是如何工作的。欢迎大家阅读:https://juejin.cn/post/7077550257344610312
    2022-03-23
    1
  • 奇奇
    老师,这个 ExecutableElement targetAsKey = getExecutable(annotation, "value"); 这一句是干嘛的,我看语义是找出所有名字是value的方法?难道不应该找的是value所指向的类吗?
    2019-04-25
    1
收起评论
显示
设置
留言
19
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部