Java获取类方法上的注解
Java获取类上的注解有下面3个方法:
- Class.getAnnotations() 获取所有的注解,包括自己声明的以及继承的
- Class.getAnnotation(Class< A > annotationClass) 获取指定的注解,该注解可以是自己声明的,也可以是继承的
- Class.getDeclaredAnnotations() 获取自己声明的注解
- 注解只有标注了@Inherited才能被子类继承
- 当某个类没有标注任何注解时,getAnnotations()和getDeclaredAnnotations()返回空数组
- 当某个注解查询不到时,getAnnotation(Class< A > annotationType)方法返回null
- 子类重写的方法,注解无法被继承,针对方法而言,getAnnotations()与getDeclaredAnnotations()返回的结果似乎永远都是一样的。
正常情况下,我们的class是 com
.cxytiandi.eureka_client.controller.ArticleController这种形式,如果用了AOP后,那么就会变成 com
.cxytiandi.eureka_client.controller.ArticleController$$EnhancerBySpringCGLIB$$3323dd1e这样了。
解决方案一
这种情况下拿到的Method也是被代理了的,所以Method上的注解自然获取不到,既然知道原因了,最简单快速的解决方法就是将多余的内容截取掉,然后重新得到一个没有被代理的Class对象,通过这个Class对象来获取Method,这样就可以获取到Method上的注解。
Class
<?>
clz
=
bean
.
getClass
();
String
fullName
=
clz
.
getName
();
if
(
fullName
.
contains
(
"EnhancerBySpringCGLIB"
)
||
fullName
.
contains
(
"$$"
))
{
fullName
=
fullName
.
substring
(
0
,
fullName
.
indexOf
(
"$$"
));
try
{
clz
=
Class
.
forName
(
fullName
);
}
catch
(
ClassNotFoundException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
Method
[]
methods
=
clz
.
getMethods
();
for
(
Method
method
:
methods
)
{
if
(
method
.
isAnnotationPresent
(
Encrypt
.
class
))
{
String
uri
=
method
.
getAnnotation
(
Encrypt
.
class
).
value
();
}
}
解决方案二
虽然问题解决了,但是还是觉得不够优雅,有没有更好的方式呢?我们可以用Spring里面提供的AnnotationUtils来读取注解。
Encrypt
encrypt
=
AnnotationUtils
.
findAnnotation
(
method
,
Encrypt
.
class
);
if
(
encrypt
!=
null
)
{
String
uri
=
encrypt
.
value
();
}
AnnotationUtils.findAnnotation()原理是什么呢?为什么它可以获取到被代理后方法上的注解呢?
要想知道原理,那就只能看源码啦,源码多,不贴出来了,贴一点点关键的就行了
首先会构建一个AnnotationCacheKey,从本地缓存中获取,如果有的话直接返回,也就意味着只要读取过就会被缓存起来:
AnnotationCacheKey
cacheKey
=
new
AnnotationCacheKey
(
method
,
annotationType
);
A result
=
(
A
)
findAnnotationCache
.
get
(
cacheKey
);
然后就是判断是否桥接方法,如果不是就直接返回,是的话则获取桥接方法的注解,如果还获取不到就通过接口来获取。
Method
resolvedMethod
=
BridgeMethodResolver
.
findBridgedMethod
(
method
);
result
=
findAnnotation
((
AnnotatedElement
)
resolvedMethod
,
annotationType
);
if
(
result
==
null
)
{
result
=
searchOnInterfaces
(
method
,
annotationType
,
method
.
getDeclaringClass
().
getInterfaces
());
}
后面就不继续下去了,最关键的代码其实是这句:
clazz = clazz.getSuperclass();
因为CGLIB代理会为目标类动态生成一个子类,所以我们要获取最原始的类,直接使用getSuperclass就可以了,跟第一种方案是一致的,只是第一种看起来有点那啥哈.....
推荐大家用AnnotationUtils去获取,这里面封装了很多的逻辑,考虑了很多场景下的问题,切莫重复造轮子。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
2018-05-27 2018第21周回顾
2017-05-27 《洞见远胜创意》听书笔记-如何获得洞见
2016-05-27 2016第22周五
2015-05-27 java开源资源
2014-05-27 第22周二
2013-05-27 2013年5月27日20:16:02
2012-05-27 Java基础语法总结2