一、ReflectionUtils工具类介绍
org.springframework.util.ReflectionUtils
是 Spring 框架提供的一个反射工具类,它封装了 Java 反射 API 的一些常用操作,使得我们能够更加方便、简洁地使用反射功能。。
1. 获取 Class 对象
ReflectionUtils
提供了多种获取 Class
对象的方法,如:
findClass(String name)
: 根据类名获取Class
对象,与Class.forName(String)
类似,但会缓存已经加载过的类。getClass(Object obj)
: 获取对象的运行时类,与obj.getClass()
等效。getUserClass(Object obj)
: 如果对象是代理对象,则获取其背后的实际类(即目标类),否则与getClass(Object)
相同。
2. 访问字段(Field)
这个工具类也简化了对字段的访问操作:
findField(Class<?> clazz, String name)
: 在给定的类及其父类中查找具有指定名称的字段。
findField(Class<?> clazz, String name, Class<?> type)
: 根据名称和类型查找字段。getField(Field field)
: 获取可访问的字段对象,如果字段是私有的,会设置其为可访问。
setField(Object obj, String name, Object value)
: 设置指定对象的字段值。getFieldValue(Object obj, String name)
: 获取指定对象的字段值。
3. 调用方法(Method)
ReflectionUtils
同样提供了方法来简化方法的调用:
findMethod(Class<?> clazz, String name, Class<?>... paramTypes)
: 查找具有指定名称和参数类型的方法。invokeMethod(Method method, Object target)
: 调用无参数方法。invokeMethod(Method method, Object target, Object... args)
: 调用带参数的方法。invokeJdbcMethod(Method method, Object target, Object... args)
: 专为 JDBC 方法设计的调用,处理 SQL 异常。makeAccessible(Method method)
: 确保方法可以访问,即使它是私有的。
4. 构造函数和实例化
这个工具类还提供了通过构造函数创建类实例的方法:
getConstructorIfAvailable(Class<?> clazz, Class<?>... paramTypes)
: 尝试获取指定参数类型的构造函数,如果找不到则返回null
。instantiateClass(Constructor<?> ctor, Object... args)
: 使用指定的构造函数和参数实例化类。
newInstance(Class<?> clazz, Object... args)
: 简化版的实例化方法,它内部会查找合适的构造函数并调用instantiateClass
。
5. 其他实用方法
isAssignable(Class<?> lhsType, Class<?> rhsType)
: 判断一个类是否可以赋值给另一个类(考虑继承关系)。doesMethodDeclareException(Method method, Class<?> exceptionType)
: 检查方法是否声明了指定类型的异常。getUniqueDeclaredMethods(Class<?> leafClass)
: 获取类中声明的所有方法,包括继承的方法,但排除重写的方法,确保每个方法只出现一次。getAllDeclaredMethods(Class<?> leafClass)
: 获取类中声明的所有方法,包括继承的方法,但不排除重写的方法。
getDeclaredMethods(Class<?> clazz)
: 获取类中直接声明的所有方法,不包括继承的方法。getDeclaredFields(Class<?> clazz)
: 获取类中直接声明的所有字段。
注意事项
虽然 ReflectionUtils
提供了很多便捷的方法,但使用反射仍然需要谨慎。反射操作可能会破坏封装性、增加性能开销,并可能引发安全问题。因此,在不需要动态访问的情况下,最好避免使用反射。
二、ReflectionUtils源码解读
以下是 ReflectionUtils
类中部分方法的代码:
import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.springframework.lang.Nullable; public abstract class ReflectionUtils { // 缓存已解析的类 private static final Class<?>[] EMPTY_CLASS_ARRAY = {}; // ... 其他常量和方法 ... // 获取类的方法,处理了类加载异常 @Nullable public static Class<?> findClass(String name) throws ClassNotFoundException { // 省略了缓存逻辑和类加载器的详细处理 return Class.forName(name, false, getDefaultClassLoader()); } // 判断方法是否声明了某个异常 public static boolean doesMethodDeclareException(Method method, Class<?> exceptionType) { Class<?>[] declaredExceptions = method.getExceptionTypes(); for (Class<?> declaredException : declaredExceptions) { if (declaredException.isAssignableFrom(exceptionType)) { return true; } } return false; } // 使字段可访问,并返回字段对象 public static Field getField(Field field) { makeAccessible(field); return field; } // 设置字段的值 public static void setField(Object obj, String fieldName, @Nullable Object value) { Field field = findField(obj.getClass(), fieldName); if (field == null) { throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); } makeAccessible(field); try { field.set(obj, value); } catch (IllegalAccessException ex) { throw new IllegalStateException("Cannot access field [" + fieldName + "] on target [" + obj + "]", ex); } } // 获取字段的值 @Nullable public static Object getFieldValue(Object obj, String fieldName) { Field field = findField(obj.getClass(), fieldName); if (field == null) { throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); } makeAccessible(field); try { return field.get(obj); } catch (IllegalAccessException ex) { throw new IllegalStateException("Cannot access field [" + fieldName + "] on target [" + obj + "]", ex); } } // 查找类中的字段 @Nullable public static Field findField(Class<?> clazz, String name) { return findField(clazz, name, null); } // 查找类中的字段,考虑字段类型 @Nullable public static Field findField(Class<?> clazz, String name, @Nullable Class<?> type) { Class<?> searchType = clazz; while (searchType != null && searchType != Object.class) { Field[] fields = searchType.getDeclaredFields(); for (Field field : fields) { if ((name == null || name.equals(field.getName())) && (type == null || type.equals(field.getType()))) { return field; } } searchType = searchType.getSuperclass(); } return null; } // ... 省略了其他方法 ... // 设置可访问性的通用方法 public static void makeAccessible(AccessibleObject accessibleObject) { if ((!Modifier.isPublic(accessibleObject.getModifiers()) || !Modifier.isPublic(accessibleObject.getDeclaringClass().getModifiers())) && !accessibleObject.isAccessible()) { accessibleObject.setAccessible(true); } } // ... 省略了其他方法 ... }
以上代码只是一个丐版,并不是 ReflectionUtils
类的完整实现。
三、ReflectionUtils的使用
获取类的私有字段值
有一个类 Person
,它有一个私有字段 name
,想要通过反射来获取这个私有字段的值。
import org.springframework.util.ReflectionUtils; public class Person { private String name; public Person(String name) { this.name = name; } // 省略其他方法... } public class ReflectionExample { public static void main(String[] args) { Person person = new Person("John Doe"); String fieldName = "name"; // 使用 ReflectionUtils 获取私有字段的值 String nameValue = (String) ReflectionUtils.getFieldValue(person, fieldName); System.out.println("Name value: " + nameValue); // 输出: Name value: John Doe } }
设置类的私有字段值
想要通过反射来设置私有字段 name
的值,可以这样:
public class ReflectionExample { public static void main(String[] args) { Person person = new Person("John Doe"); String fieldName = "name"; String newValue = "Jane Doe"; // 使用 ReflectionUtils 设置私有字段的值 ReflectionUtils.setField(person, fieldName, newValue); // 再次获取并验证字段值已更改 String updatedValue = (String) ReflectionUtils.getFieldValue(person, fieldName); System.out.println("Updated name value: " + updatedValue); // 输出: Updated name value: Jane Doe } }
调用私有方法
假设 Person
类有一个私有方法 sayHello()
,想要通过反射来调用这个方法。
import org.springframework.util.ReflectionUtils; public class Person { // ... 省略其他字段和方法 ... private void sayHello() { System.out.println("Hello, I'm a private method!"); } } public class ReflectionExample { public static void main(String[] args) { Person person = new Person("John Doe"); String methodName = "sayHello"; // 使用 ReflectionUtils 调用私有方法(无参数) ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(Person.class, methodName), person); // 输出: Hello, I'm a private method! } }
检查方法是否声明了特定异常
想要检查一个方法是否声明了抛出某个特定类型的异常,可以使用 doesMethodDeclareException
方法。
import org.springframework.util.ReflectionUtils; import java.io.IOException; public class ExampleWithException { public void methodThatThrows() throws IOException { // ... 方法实现 ... } } public class ReflectionExample { public static void main(String[] args) { boolean declaresException = ReflectionUtils.doesMethodDeclareException( ReflectionUtils.findMethod(ExampleWithException.class, "methodThatThrows"), IOException.class); System.out.println("Declares IOException: " + declaresException); // 输出: Declares IOException: true } }