SpringIoc以及set注入八種基本類型的簡單實現


主要涉及到的技術以及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文檔 ![](https://img2020.cnblogs.com/blog/1416345/202007/1416345-20200715173307717-1541196266.png)

注意!!!

第三部分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);
}

}

###執行結果 ![](https://img2020.cnblogs.com/blog/1416345/202007/1416345-20200715173333896-1820834114.png)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM