首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 反射機制工程實戰:從核心 API 到框架級應用模式

     編輯:Java 相關知識

本文結合企業級框架 (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);
    }
}

二、框架級應用模式:Hotweb MVC 處理器調用鏈

2.1 處理器實例化與屬性注入

// 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;
    }
}

2.2 動態方法分發:actionType 參數路由

// 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);
        }
    }
}

三、進階技巧:泛型擦除補償與集合操作

3.1 獲取泛型實際類型參數

// 父類定義
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,無需傳遞
}

3.2 繞過泛型擦除操作集合

// 向 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();
    }
}

五、Cassandra RowMapper 實戰:ResultSet → 實體自動映射

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+ 封裝報錯
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved