Java 反射配合介面導向設計,可實現「配置驅動、無需修改代碼即可擴展新協議/處理器」的插件化架構。本文通過一個完整的指令分發示例,展示反射動態加載類、實例化、方法調用的標準流程與異常處理。
┌─────────────┐ ┌─────────────┐ ┌──────────────────┐
│ 配置文件 │────▶│ 反射加載器 │────▶│ Operator 介面 │
│ emp.properties │ TestReflect │ │ 實現類 │
└─────────────┘ └─────────────┘ └──────────────────┘
│
▼
┌──────────────┐
│ 動態實例化 │
│ Method.invoke│
└──────────────┘
package org.bromon.reflect;
import java.util.List;
public interface Operator {
List> act(List> params);
}
// Load.java
package org.bromon.reflect;
import java.util.*;
public class Load implements Operator {
@Override public List> act(List> params) {
List r = new ArrayList<>();
r.add("加載成功");
return r;
}
}
// Store.java
package org.bromon.reflect;
public class Store implements Operator {
@Override public List> act(List> params) {
return Collections.singletonList("Store");
}
}
// Success.java
package org.bromon.reflect;
public class Success implements Operator {
@Override public List> act(List> params) {
return Collections.singletonList("操作成功");
}
}
2000=Load
2001=Store
2002=Success
package org.bromon.reflect;
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.util.*;
public class TestReflect {
/** 從屬性文件讀取類名映射 */
private String loadProtocol(String header) {
try (FileInputStream fis = new FileInputStream("emp.properties")) {
Properties prop = new Properties();
prop.load(fis);
return prop.getProperty(header);
} catch (Exception e) {
System.err.println("配置讀取失敗: " + e.getMessage());
return null;
}
}
/** 反射動態調用 */
public String response(String header, String content) {
String className = loadProtocol(header);
if (className == null) return "未知協議: " + header;
try {
// 1. 載入類 (全限定名)
String fqcn = "org.bromon.reflect." + className;
Class> clazz = Class.forName(fqcn);
// 2. 實例化 (無參構造器)
Operator operator = (Operator) clazz.getDeclaredConstructor().newInstance();
// 3. 獲取目標方法
Method method = clazz.getMethod("act", List.class);
// 4. 準備參數並調用
List args = Collections.singletonList(content);
List> result = (List>) method.invoke(operator, args);
return result.isEmpty() ? "無返回" : result.get(0).toString();
} catch (ClassNotFoundException e) {
return "類不存在: " + e.getMessage();
} catch (NoSuchMethodException e) {
return "方法簽名不匹配: " + e.getMessage();
} catch (Exception e) {
return "反射調用異常: " + e.getMessage();
}
}
public static void main(String[] args) {
TestReflect tr = new TestReflect();
System.out.println(tr.response("2000", "測試內容")); // 加載成功
System.out.println(tr.response("2001", "測試內容")); // Store
System.out.println(tr.response("9999", "測試內容")); // 未知協議
}
}
| 方法 | 初始化類 | 用途 |
|---|---|---|
| Class.forName(fqcn) | 是 (執行 static 塊) | 通用載入,需觸發靜態初始化 |
| ClassLoader.loadClass(fqcn) | 否 | 僅載入字節碼,延遲初始化 |
// 推薦:獲取聲明的無參構造器(含 private)
Constructor> ctor = clazz.getDeclaredConstructor();
ctor.setAccessible(true); // 繞過訪問檢查
Object instance = ctor.newInstance();
// 不推薦:clazz.newInstance() —— 已棄用 (Java 9),拋棄異常、不支援帶參構造器
try {
// 反射操作
} catch (ClassNotFoundException e) {
// 類路徑問題
} catch (NoSuchMethodException | NoSuchFieldException e) {
// 簽名不匹配,代碼與配置不一致
} catch (IllegalAccessException e) {
// 權限不足,需 setAccessible(true) 或模組導出
} catch (InvocationTargetException e) {
// 目標方法內部拋出異常,真實原因在 e.getCause()
Throwable cause = e.getCause();
} catch (InstantiationException e) {
// 實例化失敗(如抽象類、無無參構造器)
}
反射賦予 Java 動態性,配合介面與配置,可構建高擴展性的插件系統。生產環境需關注: