主要涉及到的技術以及API
反射、xml定義和解析、樹模型
反射可以在代碼運行狀態下動態的創建對象以及調用方法。
API:Dom4j、Class、Field、Method。
請仔細閱讀接下來的API詳解,為代碼的閱讀進行鋪墊。
Dom4j
org.dom4j.io.SAXreader - Xml讀取工具。
- Document read(InputStream is) 讀取輸入流,並返回文檔對象/文檔樹模型。
org.dom4j.Document - 文檔對象/文檔樹模型。
- Element getRootElement() 通過文檔對象,獲取xml文檔的根節點。
org.dom4j.Element - 元素/節點對象,一個Element對象就表示一個xml文檔的節點。
- String getName() 獲取當前節點的名稱。
- List<Element> elements() 獲取當前節點的所有子節點。
- String attributeValue("屬性名稱") 獲取當前節點的屬性值
Class
java.lang.Class - 類對象,該類的實例由Java虛擬機和類加載器自動構造。
- static Class forName(String className) 根據參數自定的類名創建類對象,類對象中記錄了className指定類名的信息。
- T newInstance() 創建該class對象所記錄類型的實例。
- Field getDeclaredField(String name) 根據參數指定的name獲取類型的字段/成員變量。
- Method[] getMethods() 用於獲取Class對象所表示類中的所有公共方法。
Field
java.lang.reflect.Field - 單個 字段/成員變量 對象
- void setAccessible(boolean falg)java是門安全的語言,字段默認不可暴力訪問,想要通過這種方式訪問某個字段,需要打開訪問權限,傳入true即可。
- Type getGenericType() 獲取字段類型。
Method
java.lang.reflect.Method - 用於描述獲取到的單個 成員方法 信息。
- String getName() 獲取當前方法名稱 如setName。
- Object invoke(Object obj, Object... args) 使用參數對象 obj 去調用該 Method 對象所表示的成員方法,實參傳遞 args。
- 若該 Method 對象表示Person類中setName()方法,則調用該方法就是 obj.setName()。
鋪墊完畢 上代碼
首先 - 目錄結構

pom.xml

第一部分 - Person類
展開查看
public class Person {
private int age;
private String name;
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
###第二部分 - xml文檔 
注意!!!
第三部分XmlUtil的代碼中,由於MarkDown標簽沖突原因,集合中的泛型並沒有正常顯示
如:
Map<String,Object> map = new HashMap<>();
List<Element> beans = rootElement.elements();
摘抄代碼時,還請手動添加。
第三部分 - XmlUtil類
展開查看
public class XmlUtil {
//創建Map集合,用於bean對象的存儲
Map
map = new HashMap<>();
/**
* @param xmlName 想要解析的xml文檔
* @throws Exception
*/
XmlUtil(String xmlName) throws Exception {
//加載輸入流
InputStream is = getClass().getClassLoader().getResourceAsStream(xmlName);
//創建解析器
SAXReader saxReader = new SAXReader();
//解析輸入流,得到整個文檔
Document document = saxReader.read(is);
//調用init,並將文檔樹模型傳入
init(document);
}
public void init(Document document) throws Exception {
//獲取文檔中的根元素,也就是xml中的beans標簽
Element rootElement = document.getRootElement();
//通過根元素,獲取文檔中所有的bean標簽
List<Element> beans = rootElement.elements();
//聲明Class類型的引用
Class cls;
//聲明實列引用,后續執行方法時用到
Object instance;
//聲明String類型的beanId,充當Map集合中的key
String beanId;
//依次取出bean標簽
for (Element bean:beans){
//獲取bean標簽的class屬性值
String className = bean.attributeValue("class");
//獲取bean標簽的id屬性值
beanId = bean.attributeValue("id");
//根據獲取的class屬性值創建Class對象
cls = Class.forName(className);
//根據cls記錄的類創建實列
instance = cls.newInstance();
//獲取bean標簽下的所有property標簽
List<Element> propertys = bean.elements();
//挨個取出property標簽
for (Element property : propertys){
//獲取property標簽的name屬性值
String name = property.attributeValue("name");
//然后從cls記錄的類型中獲取name中存儲的字段
Field field = cls.getDeclaredField(name);
//如果字段是private修飾,需要手動打開訪問權限
field.setAccessible(true);
//獲取這個字段的類型,用於后續賦值時的類型判斷
Type type = field.getGenericType();
//開始拼接set方法,拼接的方式是 "set"+字段 , 用於后續尋找想要使用的set方法
String methodName = "set" + name;
//獲取cls記錄類型的所有方法
Method[] methods = cls.getMethods();
String value = property.attributeValue("value");
//遍歷所有的方法,並找到吻合的set方法
for (Method method : methods){
//獲取方法名,調用String類中的compareToIgnoreCase方法與已經拼接好的 set 方法做比較
if (method.getName().compareToIgnoreCase(methodName) == 0) {
//使用已經獲取到的字段類型與標簽中讀取到的值進行比較
//這里進行String類型的比較
if (type.equals(value.getClass())) {
method.invoke(instance, value);
//如果類型不一致,則進入下一個類型判斷
}else if(type == Integer.TYPE){
int i = Integer.parseInt(value);
method.invoke(instance,i);
}
//。。。這里可以繼續if else進行類型的判斷
}
}
}
//所有流程執行完畢,將准備好的 beanId 以及 填充完畢的實列對象放入map集合中
map.put(beanId,instance);
}
}
/**
* @param beanId Map中的key
* @return 返回參數key所對應的對象/實列
*/
public Object getBean(String beanId){
return map.get(beanId);
}
//main方法中進行測試
public static void main(String[] args) throws Exception {
XmlUtil xmlUtil = new XmlUtil("beans.xml");
Object bean = xmlUtil.getBean("1002");
Person p = (Person)bean;
System.out.println(p);
}
}
###執行結果 