public Object invokeMethod(String className, String methodName, Object[] args) throws Exception {
Class<?> ownerClass = Class.forName(className);
Object owner = ownerClass.newInstance();
Class<?>[] argsClass = new Class[args.length];
for (int i = 0; i < args.length; i++) {
argsClass[i] = args[i].getClass();
}
Method method = ownerClass.getMethod(methodName, argsClass);
return method.invoke(owner, args);
}
場景:Struts 1.x Action 方法簽名為:
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
實際運行時,request 是 org.apache.catalina.connector.RequestFacade,實現了 HttpServletRequest 介面。若直接傳入實例,getMethod 會因參數類型不匹配(RequestFacade.class != HttpServletRequest.class)拋出 NoSuchMethodException。
for (int i = 0; i < args.length; i++) {
if (i == 3) { // response 位於第 4 個參數
argsClass[i] = HttpServletResponse.class;
} else {
argsClass[i] = args[i].getClass();
}
}
同理,若框架注入的是介面類型,需手動將實參類型替換為介面類型,確保 getMethod 能匹配到聲明簽名。
public class ReflectionInvoker {
private static final Map<Class<?>, Class<?>> INTERFACE_MAP = new HashMap<>();
static {
INTERFACE_MAP.put(org.apache.catalina.connector.RequestFacade.class, HttpServletRequest.class);
INTERFACE_MAP.put(org.apache.catalina.connector.ResponseFacade.class, HttpServletResponse.class);
// 可擴展更多容器實現類
}
public static Object invoke(Object target, String methodName, Object... args) throws Exception {
Class<?>[] paramTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
Class<?> actual = args[i].getClass();
// 自動映射至介面
paramTypes[i] = INTERFACE_MAP.getOrDefault(actual, actual);
}
Method method = target.getClass().getMethod(methodName, paramTypes);
return method.invoke(target, args);
}
}
getMethod 開銷。int.class vs Integer.class 需手動轉換,ClassUtils.primitiveToWrapper 可輔助。setAccessible(true) 可訪問私有方法,但需權衡安全性。反射動態調用的核心難點在於參數類型匹配。通過建立「容器實現類 → 標準介面」的映射表,或在特定位置強制指定介面類型,可優雅解決此問題,構建通用、健壯的反射調用工具。