美文网首页spring基础Java web一些收藏
JAVA反射4—工具类ReflectionUtils

JAVA反射4—工具类ReflectionUtils

作者: 小胖学编程 | 来源:发表于2020-11-11 10:12 被阅读0次

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

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

        public static void main(String[] args) {
            UserInfo userInfo = new UserInfo();
            userInfo.setName("李白");
            //找到Field对象(在缓存中获取对象)
            Field field = ReflectionUtils.findField(UserInfo.class, "name");
            ReflectionUtils.makeAccessible(field);
            //通过反射获取对象
            Object value = ReflectionUtils.getField(field, userInfo);
            System.out.println(value);
        }
    

    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);
        }
    }
    
    抛出异常.png

    相关文章

      网友评论

        本文标题:JAVA反射4—工具类ReflectionUtils

        本文链接:https://www.haomeiwen.com/subject/xfusbktx.html