重新认识Java注解
重新认识Java注解
今天Debug看源码的时候,无意间看到这么个东西
首先承认我的无知,看到这个我很惊诧。
也勾起了我的好奇心,于是有了这篇认知记录。
下面就来重新认识下注解吧!
注解的本质
关于运行时注解的信息,会在.class
文件中,并且最终以运行时数据结构存储在方法区
,也知道我们是可以通过Class
对象或者Method
对象,来获取其相应的注解信息的。
不过确实没有意识到,或者说根本就没有去猜想其背后的实现,也许是直接使用来解析注解的机会比较少吧。
现在才认识到,原来我们定义的注解, 最终使用的时候,都是以一个代理类的方式与相应的Class
或者Method
对象绑定到一起。
所有的注解,其实都是接口Annotation
子接口,而每一个@interface
的声明,最后其实就是一个普通的interface
罢了!下面请看
public @interface AnnotationDemo {
int value();
int name ();
}
public interface com.example.demo.anno.AnnotationDemo extends java.lang.annotation.Annotation {
public abstract int value();
public abstract int name();
}
从上面对一个注解类的反编译结果就能看出来,它其实就是一个普通的接口类
从接口到实例
我们是如何查找到一个类定义的那些注解然后去使用呢?
答案是:从Class
对象中,我们可以获取所有的信息
一个Class
的所有Annotation
代理类被封装到一个私有静态类AnnotationData
中
private static class AnnotationData {
// 一个Map 映射 具体的Annotation Class 和其代理类对象
final Map<Class<? extends Annotation>, Annotation> annotations;
final Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
// Value of classRedefinedCount when we created this AnnotationData instance
final int redefinedCount;
AnnotationData(Map<Class<? extends Annotation>, Annotation> annotations,
Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
int redefinedCount) {
this.annotations = annotations;
this.declaredAnnotations = declaredAnnotations;
this.redefinedCount = redefinedCount;
}
}
Class
类中有一个成员变量
private volatile transient AnnotationData annotationData;
而具体的创建动态代理对象的操作,则是懒加载的方式
public Annotation[] getAnnotations() {
// 调用 Class#annotationData方法
return AnnotationParser.toArray(annotationData().annotations);
}
private AnnotationData annotationData() {
while (true) { // retry loop
AnnotationData annotationData = this.annotationData;
int classRedefinedCount = this.classRedefinedCount;
// 如果已经初始化,并且这个类的redefinedCount和创建此AnnotationData对象时一致
// 则无需重新创建AnnotationData对象
// java.lang.instrument.Instrumentation#redefineClasses允许在运行时,重新定义类
if (annotationData != null &&
annotationData.redefinedCount == classRedefinedCount) {
return annotationData;
}
// null or stale annotationData -> optimistically create new instance
// 为null 或者已经过时了,创建一个新的实例
AnnotationData newAnnotationData = createAnnotationData(classRedefinedCount);
// try to install it
// 使用Unsafe CAS去更新字段 annotationData,直至成功
if (Atomic.casAnnotationData(this, annotationData, newAnnotationData)) {
// successfully installed new AnnotationData
return newAnnotationData;
}
}
}
创建AnnotationData
时,是通过一些native
方法,获取类相关的annotation
元信息的byte[]
数组表示,然后解析出注解接口
对应的Class
对象,最后去通过Jdk Dynamic Proxy
动态代理来创建对象
public static Annotation annotationForMap(final Class<? extends Annotation> var0, final Map<String, Object> var1) {
return (Annotation)AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
public Annotation run() {
// JDK动态代理
return (Annotation)Proxy.newProxyInstance(var0.getClassLoader(), new Class[]{var0}, new AnnotationInvocationHandler(var0, var1));
}
});
}
这样最终就创建了一个注解接口的代理类
总结
注解类就是一个普通的接口类,最终在使用时,会创建相应的代理对象,用来获取定义在注解上的一些元数据信息。
为什么要用接口?
我的理解是,接口简单、简洁,所有的方法都是抽象方法,属性都是静态常量,而我们的添加在注解上的一些信息,通常都是一些值,并不需要方法体来去做些什么。
不过使用接口来实现注解,就会有个问题,接口的字段都是静态常量,不能修改,所以注解里定义的都是方法,而动态代理类
就是为了能在运行时,调用注解定义的方法,就能获取我们定义在注解上的值。
到这里,对注解的实现已经有了一个大概的认识,不过一些细节,并没有深究,能力有限,待需要时,有机会和能力再去深究。
重新认识Java注解的更多相关文章
- Java注解
Java注解其实是代码里的特殊标记,使用其他工具可以对其进行处理.注解是一种元数据,起到了描述.配置的作用,生成文档,所有的注解都隐式地扩展自java.lang.annotation.Annotati ...
- 19.Java 注解
19.Java注解 1.Java内置注解----注解代码 @Deprecated //不推荐使用的过时方法 @Deprecated ...
- Java注解入门
注解的分类 按运行机制分: 源码注解:只在源码中存在,编译后不存在 编译时注解:源码和编译后的class文件都存在(如@Override,@Deprecated,@SuppressWarnin ...
- java注解(Annotation)解析
注解(Annotation)在java中应用非常广泛.它既能帮助我们在编码中减少错误,(比如最常见的Override注解),还可以帮助我们减少各种xml文件的配置,比如定义AOP切面用@AspectJ ...
- JAVA 注解的几大作用及使用方法详解
JAVA 注解的几大作用及使用方法详解 (2013-01-22 15:13:04) 转载▼ 标签: java 注解 杂谈 分类: Java java 注解,从名字上看是注释,解释.但功能却不仅仅是注释 ...
- attilax.java 注解的本质and 使用最佳实践(3)O7
attilax.java 注解的本质and 使用最佳实践(3)O7 1. 定义pojo 1 2. 建立注解By eclipse tps 1 3. 注解参数的可支持数据类型: 2 4. 注解处理器 2 ...
- paip.java 注解的详细使用代码
paip.java 注解的详细使用代码 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.net/att ...
- JAVA 注解的几大作用及使用方法详解【转】
java 注解,从名字上看是注释,解释.但功能却不仅仅是注释那么简单.注解(Annotation) 为我们在代码中添加信息提供了一种形式化的方法,是我们可以在稍后 某个时刻方便地使用这些数据(通过 解 ...
- 框架基础——全面解析Java注解
为什么学习注解? 学习注解有什么好处? 学完能做什么? 答:1. 能够读懂别人写的代码,特别是框架相关的代码: 2. 让编程更加简洁,代码更加清晰: 3. 让别人高看一眼. spring.mybati ...
- Java注解配置
Java注解是附加在代码中的一些元信息,用于一些工具在编译.运行时进行解析和使用,起到说明.配置的功能.注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用.包含在 java.lang.annota ...
随机推荐
- C语言学生管理系统完善版
#include<stdio.h>#include<string.h>#include <stdlib.h>#define M 100struct score ...
- CentOS之crontab
1.crontab介绍 功能说明:设置计时器. 语 法:crontab [-u <用户名称>][配置文件] 或 crontab [-u <用户名称>][-elr] 补充说明:c ...
- WEB页面实现方法
页面分类 :添加页.修改页.列表页.详情页.功能页.删除 一.添加 1) 准备tpl.action(添加页.添加页保存公用一个action),并确认是否登录才显示2) 书写添加页action代码,例如 ...
- 【Selenium07篇】python+selenium实现Web自动化:PO模型,PageObject模式!
一.前言 最近问我自动化的人确实有点多,个人突发奇想:想从0开始讲解python+selenium实现Web自动化测试,请关注博客持续更新! 这是python+selenium实现Web自动化第七篇博 ...
- ConcurrentHashMap 同步安全 的真正含义(stringbuff 是同步安全的,stringbutter 不安全)
同步安全的集合,在多线程下用到这个map是安全的,但这个安全指的是什么?线程安全指的是指get.remove.put等操作时即同一对象,同一时间只有一个线程能在这几个方法上运行,也就是说线程安全是在这 ...
- Netty服务端接收的新连接是如何绑定到worker线程池的?
更多技术分享可关注我 前言 原文:Netty服务端接收的新连接是如何绑定到worker线程池的? 前面分析Netty服务端检测新连接的过程提到了NioServerSocketChannel读完新连接后 ...
- ClassLoader类加载器浅见
类加载器 类加载器,它拿到.class文件,它会把他拆成两部分,将static数据转换成方法区的数据结构,然后把他放在了方法区之中. 然后在堆里面建一个类对象(Class,它可以用来实例化对象),然后 ...
- L24 word2vec
词嵌入基础 我们在"循环神经网络的从零开始实现"一节中使用 one-hot 向量表示单词,虽然它们构造起来很容易,但通常并不是一个好选择.一个主要的原因是,one-hot 词向量无 ...
- F. 蚂蚁装修
单点时限: 2.0 sec 内存限制: 512 MB 还有一个月就开学了,爱学习的小蚂蚁想庆祝一下!于是它要把它的“家”装修一下.首先要做的就是贴地板.小蚂蚁“家”的地面可以看成一个2∗N 的方格 , ...
- 实例讲解Springboot以Repository方式整合Redis
1 简介 Redis是高性能的NoSQL数据库,经常作为缓存流行于各大互联网架构中.本文将介绍如何在Springboot中整合Spring Data Redis,使用Repository的方式操作. ...