org.springframework.util.ReflectionUtils
是 Spring 框架提供的一个反射工具类,它封装了 Java 反射 API 的一些常用操作,使得我们能够更加方便、简洁地使用反射功能。。
ReflectionUtils
提供了多种获取 Class
对象的方法,如:
findClass(String name)
: 根据类名获取 Class
对象,与 Class.forName(String)
类似,但会缓存已经加载过的类。getClass(Object obj)
: 获取对象的运行时类,与 obj.getClass()
等效。getUserClass(Object obj)
: 如果对象是代理对象,则获取其背后的实际类(即目标类),否则与 getClass(Object)
相同。这个工具类也简化了对字段的访问操作:
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)
: 获取指定对象的字段值。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)
: 确保方法可以访问,即使它是私有的。这个工具类还提供了通过构造函数创建类实例的方法:
getConstructorIfAvailable(Class<?> clazz, Class<?>... paramTypes)
: 尝试获取指定参数类型的构造函数,如果找不到则返回 null
。instantiateClass(Constructor<?> ctor, Object... args)
: 使用指定的构造函数和参数实例化类。newInstance(Class<?> clazz, Object... args)
: 简化版的实例化方法,它内部会查找合适的构造函数并调用 instantiateClass
。isAssignable(Class<?> lhsType, Class<?> rhsType)
: 判断一个类是否可以赋值给另一个类(考虑继承关系)。doesMethodDeclareException(Method method, Class<?> exceptionType)
: 检查方法是否声明了指定类型的异常。getUniqueDeclaredMethods(Class<?> leafClass)
: 获取类中声明的所有方法,包括继承的方法,但排除重写的方法,确保每个方法只出现一次。getAllDeclaredMethods(Class<?> leafClass)
: 获取类中声明的所有方法,包括继承的方法,但不排除重写的方法。getDeclaredMethods(Class<?> clazz)
: 获取类中直接声明的所有方法,不包括继承的方法。getDeclaredFields(Class<?> clazz)
: 获取类中直接声明的所有字段。虽然 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
类的完整实现。
有一个类 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
}
}
使用 ReflectionUtils
类来处理常见的反射任务,如获取和设置私有字段的值,以及调用私有方法和检查方法异常声明。