>>分享流行的Java框架以及开源软件,对孙卫琴的《精通Spring:Java Web开发技术详解》提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 17016 个阅读者 刷新本主题
 * 贴子主题:  Spring API中JAVA反射—工具类ReflectionUtils 回复文章 点赞(0)  收藏  
作者:flybird    发表时间:2020-11-24 01:23:54     消息  查看  搜索  好友  邮件  复制  引用

      源码位置:
org.springframework.util.ReflectionUtils

     该类会使用缓存等优化反射性能。

     1. doWithMethods类上所有方法回调

     对给定类和超类的所有匹配方法执行给定的回调操作。
  源码位置:
org.springframework.util.ReflectionUtils#doWithMethods(java.lang.Class<?>, org.springframework.util.ReflectionUtils.MethodCallback)

//对给定类和超类的所有匹配方法执行给定的回调操作。
//出现在子类和超类上的同一个命名方法将出现两次,除非被指定的{@linkmethodfilter}排除。
public static void doWithMethods(Class < ?>clazz, MethodCallback mc) {
    doWithMethods(clazz, mc, null);
}
public static void doWithMethods(Class < ?>clazz, MethodCallback mc, @Nullable MethodFilter mf) {
    //获取一个类上的所有方法
    Method[] methods = getDeclaredMethods(clazz);
    //遍历方法
    for (Method method: methods) {
        //若存在mf,且方法不匹配mf,跳过
        if (mf != null && !mf.matches(method)) {
            continue;
        }
        try {
            //执行回调方法
            mc.doWith(method);
        } catch(IllegalAccessException ex) {
            throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
        }
    }
    //处理父类上的方法  
    if (clazz.getSuperclass() != null) {
        doWithMethods(clazz.getSuperclass(), mc, mf);
    }
    //处理接口上的方法
    else if (clazz.isInterface()) {
        for (Class < ?>superIfc: clazz.getInterfaces()) {
            doWithMethods(superIfc, mc, mf);
        }
    }
}

  案例:
遍历

failingMethod.getDeclaringClass()

所在的类及其超类的所有方法,来进行业务回调。    

public class TestUtils {

    public static void main(String[] args) throws NoSuchMethodException {
        //方法所在的类
        Method failingMethod = RetryService.class.getDeclaredMethod("fallback", int.class);
        ReflectionUtils.doWithMethods(failingMethod.getDeclaringClass(),
                new ReflectionUtils.MethodCallback() {
                    @Override
                    public void doWith(Method method) throws IllegalArgumentException,
                            IllegalAccessException {
                        //判断方法上是否存在某注解
                        Recover recover = AnnotationUtils.findAnnotation(method,
                                Recover.class);
                        //判断有@Recover的注解方法,方法的返回值是否和failingMethod一致
                        if (recover != null
                                && method.getReturnType().isAssignableFrom(
                                failingMethod.getReturnType())) {
                            Class<?>[] parameterTypes = method.getParameterTypes();
                            //判断参数若是多个,且第一个参数为Throw类,那么打印
                            if (parameterTypes.length > 0
                                    && Throwable.class
                                    .isAssignableFrom(parameterTypes[0])) {
                                System.out.println(method);
                            } else {
                                System.out.println(method);
                            }
                        }
                    }
                });
    }
}

  工具类定义的MethodFilter类型
//判断是否是用户定义的方法
public static final MethodFilter USER_DECLARED_METHODS =
            (method -> (!method.isBridge() && !method.isSynthetic() && method.getDeclaringClass() != Object.class));
//判断属性是否是复制的(非static、非final)
public static final FieldFilter COPYABLE_FIELDS =
            field -> !(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()));

   2. findMethod寻找Method对象

     尝试使用提供的名称和参数类型在提供的类上查找Method。搜索直到Object的所有超类。    

@Nullable
public static Method findMethod(Class < ?>clazz, String name) {
    return findMethod(clazz, name, new Class < ?>[0]);
}

@Nullable
public static Method findMethod(Class < ?>clazz, String name, @Nullable Class < ?>...paramTypes) {
    Assert.notNull(clazz, "Class must not be null");
    Assert.notNull(name, "Method name must not be null");
    Class < ?>searchType = clazz;
    while (searchType != null) {
        //利用缓存获取一个类的Mehod对象。
        Method[] methods = (searchType.isInterface() ? searchType.getMethods() : getDeclaredMethods(searchType));
        for (Method method: methods) {
            //匹配到后返回
            if (name.equals(method.getName()) && (paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) {
                return method;
            }
        }
        //获取父类,继续循环
        searchType = searchType.getSuperclass();
    }
    return null;
}

   3. findField寻找Field对象    

public static Field findField(Class < ?>clazz, @Nullable String name, @Nullable Class < ?>type) {
    Assert.notNull(clazz, "Class must not be null");
    Assert.isTrue(name != null || type != null, "Either name or type of the field must be specified");
    Class < ?>searchType = clazz;
    //当对象不为Object对象或者不为null,开始循环
    while (Object.class != searchType && searchType != null) {
        //借助缓存获取到Field对象
        Field[] fields = getDeclaredFields(searchType);
        for (Field field: fields) {
            //若匹配到,直接返回
            if ((name == null || name.equals(field.getName())) && (type == null || type.equals(field.getType()))) {
                return field;
            }
        }
        //获取父类对象
        searchType = searchType.getSuperclass();
    }
    return null;
}

  注意:获取到的Field,需要执行

field.setAccessible(true);

。    

public class Test {
    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
        Field field = ReflectionUtils.findField(TestUtils.class, "name");
        TestUtils testUtils = new TestUtils();
        testUtils.setName("tom");
        String name = (String) field.get(testUtils);
        System.out.println(name);
    }
}

             点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

抛出异常.png


----------------------------
原文链接:https://www.jianshu.com/p/0db80d2c165e

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2020-11-25 11:05:21 重新编辑]
  Java面向对象编程-->类的生命周期
  JavaWeb开发-->JSP技术详解(Ⅱ)
  JSP与Hibernate开发-->映射一对多关联关系
  Java网络编程-->创建非阻塞的HTTP服务器
  精通Spring-->Vue组件开发高级技术
  Vue3开发-->Vue组件开发基础
  Netty初识
  一篇文章让你彻底了解什么叫Netty!
  RocketMQ-Spring 为什么能成为 Spring 生态中最受欢迎的
  RocketMQ 常用消息类型
  面试官问什么是Spring循环依赖,该如何回答?
  如何编写优雅的Spring架构API
  阿里巴巴为什么能抗住90秒100亿?看完这篇你就明白了!
  SpringMVC下的JUnit4单元测试
  Spring数据验证 中@NotNull, @NotEmpty和@NotBlank之间的区别
  SpringMVC Model、ModelMap和ModelAndView的区别和用法
  阿里JAVA面试题剖析:Redis 和 memcached 有什么区别?
  Spring Cloud构建微服务架构: 消息总线
  理解 RESTful 风格的 API
  另一种缓存,Spring Boot 整合 Ehcache
  利用Spring Boot如何开发REST服务详解
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。