前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Java注解(批注)的基本原理

Java注解(批注)的基本原理

原创
作者头像
周陆军博客
发布于 2023-04-09 14:40:38
发布于 2023-04-09 14:40:38
92900
代码可运行
举报
文章被收录于专栏:前端博客前端博客
运行总次数:0
代码可运行

为什么要使用注解?

早期版本的Spring是通过XML文件的形式对整个框架进行配置的,一个缩减版的配置文件如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans">
    <!-- 配置事物管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 配置注解驱动事物管理 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

这种集中式的配置缺点也显而易见:当配置信息非常多的时候,配置文件会变得越来越大不易查看管理,特别是多人协作开发时会导致一定的相互干扰。

现在都提倡解耦、轻量化或者说微小化,那么注解就顺应了这一需求,各个包或模块在内部方法或类上使用注解即可实现指定功能,而且使用起来灰常方便,简单易懂。缺点就是不方便统一管理,如果需要修改某一类功能,则需要整体搜索逐个修改,是分散式的存在各个角落。

Spring注解替代了之前Spirng xml文件,是不是说spring的xml也是一种元数据呢?对的,spring的配置文件xml也是元数据的一种表现形式。不过xml的方式是集中式的元数据,不需要和代码绑定的,而注解是一种分散式的元数据设置方式。

关于『注解』和『XML』两种不同的配置模式,争论了好多年了,各有各的优劣,注解可以提供更大的便捷性,易于维护修改,但耦合度高,而 XML 相对于注解则是相反的。

注解是什么?

java.lang.annotation.Annotation 接口中有这么一句话,用来描述『注解』。

The common interface extended by all annotation types

这句话有点抽,个人不甚明了。

在Java中注解其实就是写在接口、类、属性、方法上的一个标签,或者说是一个特殊形式的注释,与普通的//或/**/注释不同的是:普通注释只是一个注释,而注解在代码运行时是可以被反射读取并进行相应的操作,而如果没有使用反射或者其他检查,那么注解是没有任何真实作用的,也不会影响到程序的正常运行结果。简明来说:注解是提供一种为程序元素设置元数据的方法

@Override就是一个注解,其本质就是 public interface Override extends Annotation {},注解的本质就是一个继承了 Annotation 接口的接口。有关这一点,你可以去反编译任意一个注解类,你会得到结果的。 它的作用是告诉阅读者(开发人员、编译器)这个方法重写了父类的方法,对于开发人员只是一个标志,而编译器则会多做一些事情,编译器如果发现方法标注了这个注解,就会检查这个方法到底是不是真的覆写了父类的方法。 在spring框架中加注的注解会影响到程序的运行,是因为spring内部使用反射操作了对应的注解。

程序元素就是指接口、类、属性、方法,这些都是属于程序的元素,那啥叫元数据呢?

元数据

元数据(meta data)就是描述数据的数据(data about data)。比如jpeg或者PNG图片描述数据的存储,具体参看《JPEG/Exif/TIFF格式解读(2):图片元数据保存及EXIF详解 》、《PNG文件解读(2):PNG格式文件结构与数据结构解读—解码PNG数据

  • 元数据是添加到程序元素如方法、字段、类和包上的额外信息,注解就是一种载体形式
  • 注解不能直接干扰程序代码的运行

看下官方的资料:https://www.oracle.com/technetwork/articles/hunter-meta-097643-zhs.html

术语

定义

元数据

关于数据的数据。JSR-175 的目标是在 Java 语言中提供元数据工具。

批注

一种特殊的 Java 结构,用来修饰类、方法、字段、参数、变量、构造器或包。它是 JSR-175 选择用来提供元数据的工具。

批注类型

具有特殊实施的各种命名批注

属性

由批注指定的一个特殊的元数据项目。有时可以和批注交替使用

Java 的新的元数据工具提供了从 Java 代码内部批注 Java 代码的一种标准方式。它使您能够在要说明的元素的旁边放置描述性的元数据。

注解(Annotation)是我们给代码添加的元数据。使用注解可以写出更加简洁干净的代码,同时还可以在编译期进行类型检查

JAVA注解的作用

  • 作为特定标记,用于告诉编译器一些信息
  • 编译时动态处理,如动态生成代码
  • 运行时动态处理,作为额外信息的载体,如获取注解信息

注解的分类

通常来说注解分为以下三类

  • 元注解 – java内置的注解,标明该注解的使用范围、生命周期等。
  • 标准注解 – Java提供的基础注解,标明过期的元素/标明是复写父类方法的方法/标明抑制警告。
  • 自定义注解 – 第三方定义的注解,含义和功能由第三方来定义和实现。

元注解

元注解就是用于定义注解的注解,通常用于注解的定义上,标明该注解的使用范围、生效范围等。元XX 都代表最基本最原始的东西,因此,元注解就是最基本不可分解的注解,我们不能去改变它只能使用它来定义自定义的注解

元注解包含以下五种: 

  1. @Retention:注解的生命周期
  2. @Target:注解的作用目标
  3. @Inherited:是否允许子类继承该注解
  4. @Repeatabl:是否可以重复标注。
  5. @Documented:注解是否应当被包含在 JavaDoc 文档中

其中最常用的是@Retention和@Target下面分别介绍一下这五种元注解。

@Retention

中文翻译为保留的意思,标明自定义注解的生命周期

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}

从编写Java代码到运行主要周期为源文件→ Class文件 → 运行时数据,@Retention则标注了自定义注解的信息要保留到哪个阶段,分别对应的value取值为SOURCE →CLASS→RUNTIME。

  • SOURCE 源代码java文件,注解编译期可见,生成的class文件中时丢弃 一个最简单的用法,就是自定义一个注解例如@ThreadSafe,用来标识一个类时线程安全的,就和注释的作用一样,不过更引人注目罢了。
  • CLASS class文件中会保留注解,但是jvm加载运行时就没有了(类加载阶段丢弃) 个人觉得主要是起到标记作用,还没有做实验,例如标记一个@Proxy,JVM加载时就会生成对应的代理类。
  • RUNTIME 运行时,如果想使用反射获取注解信息,则需要使用RUNTIME,反射是在运行阶段进行反射的。永久保存 反射实在运行阶段执行的,那么只有Runtime的生命周期才会保留到运行阶段,才能被反射读取,也是我们最常用的。
@Target

中文翻译为目标,描述自定义注解的使用范围——作用的目标是谁。也就是指明,你的注解到底是用来修饰方法的?修饰类的?还是用来修饰字段属性的。

允许自定义注解标注在哪些Java元素上(类、方法、属性、局部属性、参数…)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnnotation {
    String description() default "";
}

@MyAnnotation
public class AnnotationTest {
    // @MyAnnotation   用在属性上则会报错
    public String name;

    @MyAnnotation
    public void test(){}

}

value是一个数组,可以有多个取值,说明同一个注解可以同时用于标注在不同的元素上。value的取值如下

说明

TYPE

类、接口、注解、枚举

FIELD

属性

MEHOD

方法

PARAMETER

方法参数

CONSTRUCTOR

构造函数

LOCAL_VARIABLE

局部变量(如循环变量、catch参数)

ANNOTATION_TYPE

注解

PACKAGE

TYPE_PARAMETER

泛型参数  jdk1.8

TYPE_USE

任何元素  jdk1.8

@Inherited

是否可以被标注类的子类继承。被@Inherited修饰的注解是具有继承性的,在自定义的注解标注到某个类时,该类的子类会继承这个自定义注解。这里需要注意的是只有当子类继承父类的时候,注解才会被继承,类实现接口,或者接口继承接口,都是无法获得父接口上的注解声明的。正确的示例如下(通过反射获取注解)

@Repeatabl

是否可以重复标注。这个注解其实是一个语法糖,jdk1.8之前也是有办法进行重复标注的,就是使用数组属性(自定义注解会讲到)。

@Documented

是否在生成的JavaDoc文档中体现,被标注该注解后,生成的javadoc中,会包含该注解,这里就不做演示了。

标准注解

即java内置的三大注解

  • @Override 标记一个方法是覆写父类方法
  • @Deprecated 标记一个元素为已过期,避免使用——已经不再被推荐使用了,可能下一次的 JDK 版本就会删除。
    • 支持的元素类型为:CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE
  • @SuppressWarnings 不输出对应的编译警告

自定义注解

注解的本质就是一个接口,并且继承了java.lang.annotation.Annotation,内部的定义其实就是一个带默认值的方法

注解定义格式
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public @interface 注解名 {
  修饰符 返回值 属性名() 默认值;
  //TODO
}

首先注解的修饰符一般是public的,定义注解一般都是要给三方使用的,不是public的又有什么意义呢?定义的类型使用@interface,可以猜出来和接口是有一些说不清道不明的关系的,其实注解就是一个接口,在程序运行时,JVM会为其生成对应的代理类。

然后内部的定义,这个有点四不像,说是方法吧它还有一个默认值,说它是属性吧它的后面还加了一个括号,我个人还是喜欢称之为带默认返回值的接口方法,通过后面的学习我们会进一步认识它的真面目。内部的修饰符只能是public的,即使不写也默认是public的,因为它本质上就是一个接口,而接口方法的默认访问权限就是pubilc的。

注解是不能继承也不能实现其他类或接口的,本身就是一个元数据了,确实没什么必要。

返回值支持的类型如下

  • 基本类型 int float boolean byte double char logn short
  • String
  • Class
  • Enum
  • Annotation
  • 以上所有类型的数组类型

定义一个简单的接口示例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 保留至运行时
@Retention(RetentionPolicy.RUNTIME)
// 可以加在方法或者类上
@Target(value = {ElementType.TYPE,ElementType.METHOD})
public @interface RequestMapping {
    public String method() default "GET";
    public String path();
    public boolean required();
}

编译一下该注解试试

注解与反射

使用反射操作注解

反射可以获取到Class对象,进而获取到Constructor、Field、Method等实例,点开源码结构发现Class、Constructor、Field、Method等均实现了AnnotatedElement接口,AnnotatedElement接口的方法如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 判断该元素是否包含指定注解,包含则返回true
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
// 返回该元素上对应的注解,如果没有返回null
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
// 返回该元素上的所有注解,如果没有任何注解则返回一个空数组
Annotation[] getAnnotations();
// 返回指定类型的注解,如果没有返回空数组
T[] getAnnotationsByType(Class<T> annotationClass)
// 返回指定类型的注解,如果没有返回空数组,只包含直接标注的注解,不包含inherited的注解
T getDeclaredAnnotation(Class<T> annotationClass)
// 返回指定类型的注解,如果没有返回空数组,只包含直接标注的注解,不包含inherited的注解
T[] getDeclaredAnnotationsByType
// 返回该元素上的所有注解,如果没有任何注解则返回一个空数组,只包含直接标注的注解,不包含inherited的注解
Annotation[] getDeclaredAnnotations();

这就说明以上元素均可以通过反射获取该元素上标注的注解。

安利下《java反射机制原理剖析

注解的底层实现-动态代理

自定义一个注解,debuger

参考文章:

入门到精通Java注解,这一篇就够了 blog.kimzing.com/java/Java注解入门到精通-学这一篇就够了/

JAVA 注解的基本原理 https://juejin.im/post/5b45bd715188251b3a1db54f

转载本站文章《Java注解(批注)的基本原理》, 请注明出处:https://www.zhoulujun.cn/html/java/KeyConcepts/8484.html

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
为什么大部分的码农都做不了架构师?
一般来说技术团队的金字塔顶尖往往是技术最牛的人做架构师(或TL)。所以架构师在广大码农中的占比大概平均不到 20%。
数据森麟
2019/09/27
4890
为什么大部分的码农都做不了架构师?
为什么大部分的码农都做不了架构师?
一般来说技术团队的金字塔顶尖往往是技术最牛的人做架构师(或TL)。所以架构师在广大码农中的占比大概平均不到 20%。
编程珠玑
2019/09/25
5320
为什么大部分的码农都做不了架构师?
高级PHP在技术上有独当一面的能力,还需要具备哪些条件
每一个技术方向的背后都包含了众多技术细节,以开发一个分布式系统来说,需要分布式存储/数据库/缓存、中间件、RPC、消息系统、分布式一致性处理等多种技术。怎么去解决这些问题呢?
友儿
2022/09/11
3420
什么样的架构师才是真正的架构师?
  很多的创业公司,一人身兼数职的情形还是很常见的。至少,我是经历过的,一个人包办了所有的开发过程,连测试我都做了,绝对的一条龙,但是经常踩钢丝、骑独轮车总会有失足的时候,结果有一次,从我手里发出去的光盘母盘,含有病毒僵尸,以至于被迫收回已经推上市场的2万张光盘,从那之后,我的心脏就开始变得无比坚强,现在就是整个后台服务都瘫痪了,我也只是微微一笑。其实,一个人身兼架构师和程序员,甚至多种角色,没什么不妥,后面还会讲这个话题,这种现象不是中国特色,跟国外是完全接轨的。我曾经跟米国的一个工程师在msn中聊过类似的话题,发现他们的路子跟咱们没什么不同,在IT这个行业,我们跟世界的差距只有1天,他们刚弄出来的新东西,我们这里第2天保准见得到。
java架构师
2018/08/23
4400
说一说PHP7性能的变化
Opcache Preloading Opcache 预加载 新增 Opcache 预加载支持。预加载是在模块初始化的时候,将库和框架加载到 OPCache 中的过程
友儿
2022/09/11
8420
架构师之路:从Java码农到年薪八十万的架构师
可以说,Java是现阶段中国互联网公司中,覆盖度最广的研发语言,掌握了Java技术体系,不管在成熟的大公司,快速发展的公司,还是创业阶段的公司,都能有立足之地。
美的让人心动
2018/08/10
5680
架构师之路:从Java码农到年薪八十万的架构师
一份Java程序员进阶架构师的秘籍,你离架构师还差多远
Java架构师,首先要是一个Java程序员,熟练使用各种框架,并知道它们实现的原理。jvm虚拟机原理、调优,懂得jvm能让你写出性能更好的代码;池技术,什么对象池,怎么解决并发量、连接池,线程池。
慕容千语
2019/06/11
6750
七年的资深架构师告诉你成为架构师的知识体系
架构师是一个充满挑战的职业,知识面的宽窄往往决定着一个架构师的架构能力 知识面的宽广对于一名出色的架构师来说是必不可少的技能,也许很多人对架构的理解还停留在设计模式,重构,SOA等等的软件层面,然而这仅仅是非常基本的东西,架构师的脑子里不光需要知道让软件如何高效的运行,还需要知道如何去结合网络,存储,甚至一些文件系统的特性,比如GFS,NFS,XFS,NTFS等等,而且架构师还需要知道一些编程语言的特性,C,C++,Java,PHP,Python,Lisp,JS等等,现在是一个混合编程的时代,只了解一种语
Java架构
2018/05/04
1.9K0
七年的资深架构师告诉你成为架构师的知识体系
阿里十年的Java架构师用一张图告诉你什么是系统架构师
这张图从架构师的综合能力、岗位认识、岗位职责等方面,清楚的画出了作为一个架构的基本准则。人人都想成为架构师,可作为架构你达到了上面的要求了吗?
美的让人心动
2018/09/27
1.3K0
为什么大部分码农做不了软件架构师?
小团队一般 10 人左右,其中常常是技术最牛的人做架构师(或TL)。所以,架构师在广大码农中的占比大概平均不到 10%。而架构师也可以分为初级、中级、高级三档,江湖上真正高水平的软件架构师就更少了。
芋道源码
2019/05/15
5070
为什么大部分码农做不了软件架构师?
没有架构师的命,却得了架构师的病!
小团队一般 10 人左右,其中常常是技术最牛的人做架构师(或 TL)。所以,架构师在广大码农中的占比大概平均不到 10%。
架构师修炼
2020/08/27
5750
没有架构师的命,却得了架构师的病!
通往架构师路上的经验总结
我先介绍一下我的新同事,据说他是美国篮球运动员詹姆斯的死忠粉,公司好多同事都这么叫他James,有8年开发经验的架构师,之前在AL待过,我一听说是AL的,啧啧啧........,就有种莫名的种亲切感,就立马找新同事聊了起来。我们在空余的时间聊了很久,也聊了好多。毕竟之前都在AL待过,感觉话题还是有的。
AI乔治
2018/07/13
5080
百度、阿里、腾讯等一线互联网架构师都在用的技术体系
可以说,Java是现阶段中国互联网公司中,覆盖度最广的研发语言,掌握了Java技术体系,不管在成熟的大公司,快速发展的公司,还是创业阶段的公司,都能有立足之地。
技术zhai
2018/09/17
1.6K0
百度、阿里、腾讯等一线互联网架构师都在用的技术体系
通往架构师路上的经验总结
我先介绍一下我的新同事,据说他是美国篮球运动员詹姆斯的死忠粉,公司好多同事都这么叫他James,有8年开发经验的架构师,之前在AL待过,我一听说是AL的,啧啧啧........,就有种莫名的种亲切感,就立马找新同事聊了起来。我们在空余的时间聊了很久,也聊了好多。毕竟之前都在AL待过,感觉话题还是有的。
烂猪皮
2018/08/03
2800
通往架构师路上的经验总结
天天写业务代码,如何成为Java架构师?
因为现今是一个信息时代,大量的信息都是需要存储并检索的,数据库设计的不好,将会严重影响系统的性能,而这一点往往会被我们的设计人员忽略,他们只知道遵守那些范式而不会结合数据的特性去设计数据库。
美的让人心动
2018/09/20
4650
天天写业务代码,如何成为Java架构师?
阿里资深技术专家总结:要怎样努力才可以成为公司主力架构师
最近有好多人问我说:“George,怎样才能成为公司里的前线主力架构师,我现在在公式已经干了快五年了,现在还是一个默默无闻的程序员,我也通过很多种渠道来突破我现在瓶疾,但就是走不出来,技术也一直没有突破上去,我真的是没有办法了,通过朋友推荐介绍,说您这里可以解决我的技术瓶疾,所以我想请你帮我突破一下技术方面上的瓶疾。”
美的让人心动
2018/09/20
5970
阿里资深技术专家总结:要怎样努力才可以成为公司主力架构师
分享我这8年,是如何一步一步走向架构师的
摘要:心血经验分享,架构师更多的是一个不断学习,不断积累的过程,希望可以帮到同行业的朋友们
Java知音
2018/11/15
1K0
前阿里P8架构师:精准定制Java架构师学习计划!
可以说,Java是现阶段中国互联网公司中,覆盖度最广的研发语言,掌握了Java技术体系,不管在成熟的大公司,快速发展的公司,还是创业阶段的公司,都能有立足之地。
美的让人心动
2018/06/22
6030
你离架构师还有多远?
  软件架构师在整个软件开发过程中都起着重要的作用,并随着开发进程的推进而其职责或关注点不断地变化,总结下面几点。   在需求阶段,软件架构师主要负责理解和管理非功能性系统需求,比如软件的可维护性、性能、复用性、可靠性、有效性和可测试性等等,此外,架构师还要经常审查客户及市场人员所提出的需求,确认开发团队所提出的设计;   在需求越来越明确后,架构师的关注点开始转移到组织开发团队成员和开发过程定义上;   在软件设计阶段,架构师负责对整个软件体系结构、关键构件、接口和开发政策的设计;   在编码阶段,架
欢醉
2018/04/19
8800
你离架构师还有多远?
『干货分享』Java程序员月薪达到三万, 需要掌握哪些技术?1.架构师应不应该写代码2.为什么别人的系统总是那么烂3.成为架构师最困难的门槛是什么?4.如何更高效的学习?5.快速成为架构师的学习路线一
1.架构师应不应该写代码 合格的程序员对于明确分配的任务会完成的很好,但是大部分情况下“架构”这个词意味着架构师并不会涉及太多细节,架构图和代码实现之间总还是有些距离,你无法保证所有人都会正确的理解你的设计,或者是程序员写代码时遇到障碍时会立刻想出足够优雅的解决方案。 在我看来,写代码的架构师更像是在做后勤保障的工作:在代码中第一时间发现可能存在的问题,向其他人提出警告,或是给予其他人改进的意见,必要的时候或是给其他人演示一下正确的姿势。 大部分情况下我作为架构师并不需要揽下“核心模块”开发这种工作,毕竟我
美的让人心动
2018/06/14
5010
推荐阅读
相关推荐
为什么大部分的码农都做不了架构师?
更多 >
LV.2
荷培信息科技(上海)有限公司后端开发工程师
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验