zoukankan      html  css  js  c++  java
  • Java获取类方法上的注解

     Java获取类上的注解有下面3个方法:

    • Class.getAnnotations() 获取所有的注解,包括自己声明的以及继承的
    • Class.getAnnotation(Class< A > annotationClass) 获取指定的注解,该注解可以是自己声明的,也可以是继承的
    • Class.getDeclaredAnnotations() 获取自己声明的注解
    1. 注解只有标注了@Inherited才能被子类继承
    2. 当某个类没有标注任何注解时,getAnnotations()和getDeclaredAnnotations()返回空数组
    3. 当某个注解查询不到时,getAnnotation(Class< A > annotationType)方法返回null
    4. 子类重写的方法,注解无法被继承,针对方法而言,getAnnotations()与getDeclaredAnnotations()返回的结果似乎永远都是一样的。 
    如果类被代理,如何获取到类的注解呢?

    正常情况下,我们的class是 com.cxytiandi.eureka_client.controller.ArticleController这种形式,如果用了AOP后,那么就会变成 com.cxytiandi.eureka_client.controller.ArticleController$$EnhancerBySpringCGLIB$$3323dd1e这样了。

    解决方案一

    这种情况下拿到的Method也是被代理了的,所以Method上的注解自然获取不到,既然知道原因了,最简单快速的解决方法就是将多余的内容截取掉,然后重新得到一个没有被代理的Class对象,通过这个Class对象来获取Method,这样就可以获取到Method上的注解。

    1. Class<?> clz = bean.getClass();

    2. String fullName = clz.getName();

    3. if (fullName.contains("EnhancerBySpringCGLIB") || fullName.contains("$$")) {

    4. fullName = fullName.substring(0, fullName.indexOf("$$"));

    5. try {

    6. clz = Class.forName(fullName);

    7. } catch (ClassNotFoundException e) {

    8. throw new RuntimeException(e);

    9. }

    10. }

    11. Method[] methods = clz.getMethods();

    12. for (Method method : methods) {

    13. if (method.isAnnotationPresent(Encrypt.class)) {

    14. String uri = method.getAnnotation(Encrypt.class).value();

    15. }

    16. }

    解决方案二

    虽然问题解决了,但是还是觉得不够优雅,有没有更好的方式呢?我们可以用Spring里面提供的AnnotationUtils来读取注解。

    1. Encrypt encrypt = AnnotationUtils.findAnnotation(method, Encrypt.class);

    2. if (encrypt != null) {

    3. String uri = encrypt.value();

    4. }

    AnnotationUtils.findAnnotation()原理是什么呢?为什么它可以获取到被代理后方法上的注解呢?

    要想知道原理,那就只能看源码啦,源码多,不贴出来了,贴一点点关键的就行了

    首先会构建一个AnnotationCacheKey,从本地缓存中获取,如果有的话直接返回,也就意味着只要读取过就会被缓存起来:

    1. AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType);

    2. A result = (A) findAnnotationCache.get(cacheKey);

    然后就是判断是否桥接方法,如果不是就直接返回,是的话则获取桥接方法的注解,如果还获取不到就通过接口来获取。

    1. Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);

    2. result = findAnnotation((AnnotatedElement) resolvedMethod, annotationType);

    3. if (result == null) {

    4. result = searchOnInterfaces(method, annotationType, method.getDeclaringClass().getInterfaces());

    5. }

    后面就不继续下去了,最关键的代码其实是这句:

    1. clazz = clazz.getSuperclass();

    因为CGLIB代理会为目标类动态生成一个子类,所以我们要获取最原始的类,直接使用getSuperclass就可以了,跟第一种方案是一致的,只是第一种看起来有点那啥哈.....

    推荐大家用AnnotationUtils去获取,这里面封装了很多的逻辑,考虑了很多场景下的问题,切莫重复造轮子。

  • 相关阅读:
    计算机基础
    如何增加一个IT产品的用户黏性
    计算机相关专业一门课程一个案例
    【2012年6月14日】中兴发布Grand(智观)N970
    bmp格式浅析
    3Dbook的使用
    中英文翻译格式
    软件学习书籍推荐
    WEB开发基础
    PHP学习
  • 原文地址:https://www.cnblogs.com/doit8791/p/10928848.html
Copyright © 2011-2022 走看看