Java代碼實現依賴注入

這裏將模仿Spring實現一種基於xml配置文件的依賴注入機制。文件中將實現3中注入,一是單值注入,包括int,floatdoublechar等,也包括String注入;二是Java容器注入,包括ListSetMap三種容器的注入,最後一種是java bean對象注入。
實現的機制是,使用Dom4jxml配置文件進行解析,這裏使用dom4jElement Handler機制,一種類似與責任鏈模式的實現機制;對於java對象的構建使用反射機制,這裏主要是針對得到的類的Field進行set賦值。我試圖通過調用Methodinvoke方法調用類本身的setter方法,但是由於通過xml解析得到的值都是String,如果將這些String動態的轉換爲相應的確定類型是個難點,Methodinvoke方法,如果形參是int,而傳入java.lang.Integer,它不會認,所以嘗試失敗,只能通過Fieldset方法傳入特定值。

 

配置文件setting.xml
<?xml version="1.0" encoding="UTF-8"?>

 

<beans>

    <bean id="me" class="com.zj.ioc.di.imp.Person">

       <property name="name">

           <value>ZJ</value>

       </property>

       <property name="age">

           <value>26</value>

       </property>

       <property name="height">

           <value>1.78</value>

       </property>

    </bean>

    <bean id="you" class="com.zj.ioc.di.imp.Person">

       <property name="name">

           <value>Mary</value>

       </property>

       <property name="age">

           <value>27</value>

       </property>

       <property name="height">

           <value>1.66</value>

       </property>

    </bean>

    <bean id="myList" class="com.zj.ioc.di.imp.ListOne">

       <property name="msg">

           <list>

              <value>java</value>

              <value>c</value>

              <value>windows</value>

           </list>

       </property>

    </bean>

    <bean id="mySet" class="com.zj.ioc.di.imp.SetOne">

       <property name="msg">

           <set>

              <value>tom</value>

              <value>cat</value>

              <value>dog</value>

           </set>

       </property>

    </bean>

    <bean id="myMap" class="com.zj.ioc.di.imp.MapOne">

       <property name="msg">

           <map>

              <entry key="c">

                  <value>CHINA</value>

              </entry>

              <entry key="j">

                  <value>JAPAN</value>

              </entry>

              <entry key="k">

                  <value>KOREA</value>

              </entry>

           </map>

       </property>

    </bean>

    <bean id="us" class="com.zj.ioc.di.imp.Persons">

       <property name="i">

           <ref bean="me" />

       </property>

       <property name="u">

           <ref bean="you" />

       </property>

    </bean>

</beans>

 

依據setting.xml,這裏將構建兩個Person類的實例meyou
Person.java
package com.zj.ioc.di.imp;

 

public class Person {

    private String name;

    private int age;

    private float height;

 

    public String getName() {return name;}

    public void setName(String name) {this.name = name;}

    public int getAge() {return age;}

    public void setAge(int age) {this.age = age;}

    public float getHeight() {return height;}

    public void setHeight(float height) {this.height = height;}

}

緊接着,構建一個ListOne的實例myList
ListOne.java
package com.zj.ioc.di.imp;

import java.util.List;

 

public class ListOne {

    private List<String> msg;

 

    public List<String> getMsg() {return msg;}

    public void setMsg(List<String> msg) {this.msg = msg;}

}

緊接着,構建一個SetOne的實例mySet
SetOne.java
package com.zj.ioc.di.imp;

import java.util.Set;

 

public class SetOne {

    private Set<String> msg;

 

    public Set<String> getMsg() {return msg;}

    public void setMsg(Set<String> msg) {this.msg = msg;}

}
緊接着,構建一個MapOne的實例myMap
MapOne.java
package com.zj.ioc.di.imp;

import java.util.Map;

 

public class MapOne {

    private Map<String,String> msg;

 

    public Map<String, String> getMsg() {return msg;}

    public void setMsg(Map<String, String> msg) {this.msg = msg;}

}
最後構建一個Persons類的實例us,其中包含meyou兩個已經構建好的對象:
Persons.java
package com.zj.ioc.di.imp;

 

public class Persons {

    private Person i;

    private Person u;

   

    public Person getI() {return i;}

    public void setI(Person i) {this.i = i;}

    public Person getU() {return u;}

    public void setU(Person u) {this.u = u;}

}

 

主要的實現機制是(代碼BeanFactory.java以及工程見附件),
1.通過一個HashMap保存構造好的對象,key就是beanid屬性,value就是這個對象;
private Map<String, Object> beanMap = new HashMap<String, Object>();
……
public Object getBean(String beanId) {

    Object obj = beanMap.get(beanId);

    return obj;

}
查詢時
BeanFactory factory = new BeanFactory();

factory.init("setting.xml");

Person p1 = (Person) factory.getBean("me");

 

2.init方法讀入配置文件setting.xml,並直接定位到beans下的bean元素,並實例化一個ElementHandler對其處理。
public void init(String xmlUri) throws Exception {

    SAXReader saxReader = new SAXReader();

    File file = new File(xmlUri);

    try {

       saxReader.addHandler("/beans/bean", new BeanHandler());

       saxReader.read(file);

    } catch (DocumentException e) {

       System.out.println(e.getMessage());

    }

}

 

3.ElementHandlerdom4jElementHandler接口有兩個方法,一個是onStart(),它主要用於處理該元素的屬性以及動態增加新的Handler類;另一個是onEnd(),它主要用於獲得該元素的Text文本以及刪除已添加的Handler
BeanHandler
private class BeanHandler implements ElementHandler {

    Object obj = null;

 

    public void .Start(ElementPath path) {

       Element beanElement = path.getCurrent();

       Attribute classAttribute = beanElement.attribute("class");

 

       Class<?> bean = null;

       try {

           bean = Class.forName(classAttribute.getText());

       } catch (ClassNotFoundException e) {

           e.printStackTrace();

       }

       Field fields[] = bean.getDeclaredFields();

       Map<String, Field> mapField = new HashMap<String, Field>();

       for (Field field : fields)

           mapField.put(field.getName(), field);

       try {

           obj = bean.newInstance();

       } catch (InstantiationException e) {

           e.printStackTrace();

       } catch (IllegalAccessException e) {

           e.printStackTrace();

       }

 

       path.addHandler("property", new PropertyHandler(mapField, obj));

    }

 

    public void .End(ElementPath path) {

       Element beanElement = path.getCurrent();

       Attribute idAttribute = beanElement.attribute("id");

       beanMap.put(idAttribute.getText(), obj);

       path.removeHandler("property");

    }

}
   
PropertyHandler
private class PropertyHandler implements ElementHandler {

    Map<String, Field> mapField;

    Object obj;

 

    public PropertyHandler(Map<String, Field> mapField, Object obj) {

       this.mapField = mapField;

       this.obj = obj;

    }

 

    public void .Start(ElementPath path) {

       Element propertyElement = path.getCurrent();

       Attribute nameAttribute = propertyElement.attribute("name");

       path.addHandler("value", new ValueHandler(mapField, obj,

              nameAttribute));

       path.addHandler("list", new ListHandler(mapField, obj,

              nameAttribute));

       path.addHandler("set", new SetHandler(mapField, obj,

              nameAttribute));

       path.addHandler("map", new MapHandler(mapField, obj,

              nameAttribute));

       path.addHandler("ref", new RefHandler(mapField, obj,

              nameAttribute));

    }

 

    public void .End(ElementPath path) {

       path.removeHandler("value");

       path.removeHandler("list");

       path.removeHandler("set");

       path.removeHandler("map");

       path.removeHandler("ref");

    }

}

 

根據setting.xml,我們可以得到各種注入元素的Handler類處理流程圖。

 

4. setFieldValue()基於反射機制和相應的類信息得到Field的類型,並根據setting.xml設置它的值。
private void setFieldValue(Object obj, Field field, String value) {

    String fieldType = field.getType().getSimpleName();

    try {

       if (fieldType.equals("int"))

           field.setInt(obj, new Integer(value));

       else if (fieldType.equals("float"))

           field.setFloat(obj, new Float(value));

       else if (fieldType.equals("boolean"))

           field.setBoolean(obj, new Boolean(value));

       else if (fieldType.equals("char"))

           field.setChar(obj, value.charAt(0));

       else if (fieldType.equals("double"))

           field.setDouble(obj, new Double(value));

       else if (fieldType.equals("long"))

           field.setLong(obj, new Long(value));

       else

           field.set(obj, value);

    } catch (IllegalArgumentException e) {

       e.printStackTrace();

    } catch (IllegalAccessException e) {

       e.printStackTrace();

    }

}

 

private void setFieldValue(Object obj, Field field, List<String> value) {

    try {

       field.set(obj, value);

    } catch (IllegalArgumentException e) {

       e.printStackTrace();

    } catch (IllegalAccessException e) {

       e.printStackTrace();

    }

}

 

5.測試
public static void main(String[] args) {

    try {

       BeanFactory factory = new BeanFactory();

       factory.init("setting.xml");

 

       Person p1 = (Person) factory.getBean("me");

       System.out.print(p1.getName() + " ");

       System.out.print(p1.getAge() + " ");

       System.out.println(p1.getHeight());

 

       Person p2 = (Person) factory.getBean("you");

       System.out.print(p2.getName() + " ");

       System.out.print(p2.getAge() + " ");

       System.out.println(p2.getHeight());

 

       ListOne list = (ListOne) factory.getBean("myList");

       System.out.println(list.getMsg());

 

       SetOne set = (SetOne) factory.getBean("mySet");

       System.out.println(set.getMsg());

 

       MapOne map = (MapOne) factory.getBean("myMap");

       System.out.println(map.getMsg());

 

       Persons us = (Persons) factory.getBean("us");

       System.out.println(us.getI());

       System.out.println(us.getU());

    } catch (Exception e) {

       e.printStackTrace();

    }

}
測試結果:
ZJ 26 1.78

Mary 27 1.66

[java, c, windows]

[cat, tom, dog]

{c=CHINA, j=JAPAN, k=KOREA}

com.zj.ioc.di.imp.Person@1a5ab41

com.zj.ioc.di.imp.Person@18e3e60
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章