本文結合企業級框架 (Hotweb MVC) 實際代碼,系統演示反射機制在動態實例化、屬性注入、方法調用、泛型擦除補償、數組/集合操作等工程場景的標準化用法與封裝模式。
public final class ReflectionUtils {
// 1. 獲取 Class 對象 (緩存優化)
private static final Map<String, Class<?>> CLASS_CACHE = new ConcurrentHashMap<>();
public static Class<?> forName(String className) {
return CLASS_CACHE.computeIfAbsent(className, name -> {
try { return Class.forName(name, true, Thread.currentThread().getContextClassLoader()); }
catch (ClassNotFoundException e) { throw new IllegalArgumentException("Class not found: " + name, e); }
});
}
// 2. 實例化 (支持構造參數)
public static <T> T newInstance(Class<T> clazz, Object... args) {
try {
Constructor<T> ctor = Arrays.stream(clazz.getDeclaredConstructors())
.filter(c -> c.getParameterCount() == args.length)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No matching constructor"));
ctor.setAccessible(true);
return ctor.newInstance(args);
} catch (Exception e) { throw new RuntimeException(e); }
}
// 3. 方法調用 (緩存 Method 對象)
private static final Map<String, Method> METHOD_CACHE = new ConcurrentHashMap<>();
public static Object invokeMethod(Object target, String methodName, Object... args) {
Class<?> clazz = target.getClass();
String key = clazz.getName() + "#" + methodName + "#" + Arrays.toString(args);
Method method = METHOD_CACHE.computeIfAbsent(key, k -> {
try {
Method m = clazz.getDeclaredMethod(methodName,
Arrays.stream(args).map(Object::getClass).toArray(Class[]::new));
m.setAccessible(true);
return m;
} catch (NoSuchMethodException e) { throw new IllegalArgumentException(e); }
});
try { return method.invoke(target, args); }
catch (Exception e) { throw new RuntimeException(e); }
}
// 4. 字段讀寫 (支持私有、靜態)
public static void setField(Object target, String fieldName, Object value) {
try {
Field field = findField(target.getClass(), fieldName);
field.setAccessible(true);
field.set(target, value);
} catch (Exception e) { throw new RuntimeException(e); }
}
public static Object getField(Object target, String fieldName) {
try {
Field field = findField(target.getClass(), fieldName);
field.setAccessible(true);
return field.get(target);
} catch (Exception e) { throw new RuntimeException(e); }
}
private static Field findField(Class<?> clazz, String name) {
while (clazz != null) {
try { return clazz.getDeclaredField(name); }
catch (NoSuchFieldException e) { clazz = clazz.getSuperclass(); }
}
throw new IllegalArgumentException("Field not found: " + name);
}
}
// HandlerParser.java - 配置驅動的處理器創建
public class HandlerParser {
public Handler parse(String handlerId) {
// 1. 從 HandlerModule.xml 讀取配置
Element handlerElem = configDom.getElementById(handlerId);
String className = handlerElem.attributeValue("class");
String scope = handlerElem.attributeValue("scope"); // singleton/prototype
// 2. 反射實例化
Class<?> handlerClass = ReflectionUtils.forName(className);
Handler handler = (Handler) ReflectionUtils.newInstance(handlerClass);
// 3. 屬性注入 (Setter 注入)
List<Element> props = handlerElem.elements("property");
for (Element prop : props) {
String name = prop.attributeValue("name");
String value = prop.attributeValue("value");
String ref = prop.attributeValue("ref");
Object injectValue = ref != null ? getBean(ref) : convertValue(value,
ReflectionUtils.getFieldType(handlerClass, name));
ReflectionUtils.setField(handler, name, injectValue);
}
// 4. 單例緩存
if ("singleton".equals(scope)) handlerCache.put(handlerId, handler);
return handler;
}
}
// DispatchServlet.java - 請求分發核心
public class DispatchServlet extends HttpServlet {
protected void service(HttpServletRequest req, HttpServletResponse resp) {
// 1. 解析 handlerId、actionType
String handlerId = req.getParameter("handlerId");
String actionType = req.getParameter("actionType"); // 默認 prepareDisplay
// 2. 獲取/創建 Handler
Handler handler = handlerParser.parse(handlerId);
// 3. 反射調用對應方法
try {
Method actionMethod = handler.getClass().getMethod(actionType,
HttpServletRequest.class, HttpServletResponse.class);
actionMethod.setAccessible(true);
actionMethod.invoke(handler, req, resp);
} catch (NoSuchMethodException e) {
// 降級到默認方法
invokeDefault(handler, req, resp);
} catch (Exception e) {
handleError(e, req, resp);
}
}
}
// 父類定義
public abstract class BaseDao<T> {
private Class<T> entityClass;
@SuppressWarnings("unchecked")
public BaseDao() {
// 關鍵:通過獲取父類泛型參數實現
ParameterizedType superType = (ParameterizedType) getClass().getGenericSuperclass();
this.entityClass = (Class<T>) superType.getActualTypeArguments()[0];
}
public Class<T> getEntityClass() { return entityClass; }
}
// 子類使用
public class UserDao extends BaseDao<User> {
// 自動獲得 User.class,無需傳遞
}
// 向 List<Integer> 中插入 String (演示擦除本質)
List<Integer> intList = new ArrayList<>();
Method addMethod = intList.getClass().getMethod("add", Object.class);
addMethod.invoke(intList, "String Value"); // 運行時成功,編譯期報錯
System.out.println(intList); // [String Value]
// 修改數組長度 (反射創建新數組並複製)
int[] arr = {1, 2, 3};
int[] newArr = (int[]) Array.newInstance(int.class, 5);
System.arraycopy(arr, 0, newArr, 0, arr.length);
// newArr: [1, 2, 3, 0, 0]
public final class NameConverter {
// 數據庫列名(下劃線) → Java 屬性名(駝峰)
// user_name → userName, USER_ID → userId
public static String toCamelCase(String underscoreName) {
if (!underscoreName.contains("_"))
return underscoreName.substring(0, 1).toLowerCase() + underscoreName.substring(1).toLowerCase();
StringBuilder sb = new StringBuilder();
String[] parts = underscoreName.toLowerCase().split("_");
for (int i = 0; i < parts.length; i++) {
if (parts[i].isEmpty()) continue;
if (i == 0) sb.append(parts[i]);
else sb.append(Character.toUpperCase(parts[i].charAt(0))).append(parts[i].substring(1));
}
return sb.toString();
}
// Java 屬性名 → 數據庫列名
// userName → user_name, userId → user_id
public static String toUnderscoreCase(String camelName) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < camelName.length(); i++) {
char c = camelName.charAt(i);
if (Character.isUpperCase(c)) {
if (i > 0) sb.append('_');
sb.append(Character.toLowerCase(c));
} else {
sb.append(c);
}
}
return sb.toString();
}
}
public class RowMapperUtils {
public static <T> T mapRow(Row row, Class<T> entityClass) {
T entity = ReflectionUtils.newInstance(entityClass);
Map<String, PropertyDescriptor> props = getPropertyDescriptors(entityClass);
ColumnDefinitions cols = row.getColumnDefinitions();
for (Definition def : cols) {
String columnName = def.getName().toLowerCase();
String propName = NameConverter.toCamelCase(columnName);
if (props.containsKey(propName)) {
Object value = extractValue(row, def.getType(), columnName);
try {
props.get(propName).getWriteMethod().invoke(entity, value);
} catch (Exception e) { log.warn("Set property failed: {}", propName, e); }
}
}
return entity;
}
// 支持基本類型、集合(List/Set/Map)、UDT、Tuple 等複雜類型提取
private static Object extractValue(Row row, DataType type, String column) { ... }
}
| 檢查項 | 標準做法 | 反面教材 |
|---|---|---|
| Class/Method/Field 緩存 | ConcurrentHashMap 緩存,啟動預熱 | 熱路徑每次 getDeclaredMethod |
| setAccessible(true) | 框架內部封裝,業務代碼禁用 | Controller/Service 直接調用 |
| 異常處理 | 統一包裝為 RuntimeException,保留堆棧 | 拋出 checked exception 污染業務 |
| 性能敏感路徑 | 改用 MethodHandle/代碼生成 | 核心交易鏈路大量反射 |
| 模塊化兼容 | 模塊聲明 opens、--add-opens 配置 | 忽略 JDK 9+ 封裝報錯 |