美文网首页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