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;
 
publicclass Person {
    private String name;
    privateintage;
    privatefloatheight;
 
    public String getName() {returnname;}
    publicvoid setName(String name) {this.name = name;}
    publicint getAge() {returnage;}
    publicvoid setAge(int age) {this.age = age;}
    publicfloat getHeight() {returnheight;}
    publicvoid setHeight(float height) {this.height = height;}
}
緊接着,構建一個ListOne的實例myList
ListOne.java
package com.zj.ioc.di.imp;
import java.util.List;
 
publicclass ListOne {
    private List<String> msg;
 
    public List<String> getMsg() {returnmsg;}
    publicvoid setMsg(List<String> msg) {this.msg = msg;}
}
緊接着,構建一個SetOne的實例mySet
SetOne.java
package com.zj.ioc.di.imp;
import java.util.Set;
 
publicclass SetOne {
    private Set<String> msg;
 
    public Set<String> getMsg() {returnmsg;}
    publicvoid setMsg(Set<String> msg) {this.msg = msg;}
}
緊接着,構建一個MapOne的實例myMap
MapOne.java
package com.zj.ioc.di.imp;
import java.util.Map;
 
publicclass MapOne {
    private Map<String,String> msg;
 
    public Map<String, String> getMsg() {returnmsg;}
    publicvoid setMsg(Map<String, String> msg) {this.msg = msg;}
}
最後構建一個Persons類的實例us,其中包含meyou兩個已經構建好的對象:
Persons.java
package com.zj.ioc.di.imp;
 
publicclass Persons {
    private Person i;
    private Person u;
   
    public Person getI() {returni;}
    publicvoid setI(Person i) {this.i = i;}
    public Person getU() {returnu;}
    publicvoid 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對其處理。
publicvoid 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
privateclass BeanHandler implements ElementHandler {
    Object obj = null;
 
    publicvoid .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));
    }
 
    publicvoid .End(ElementPath path) {
       Element beanElement = path.getCurrent();
       Attribute idAttribute = beanElement.attribute("id");
       beanMap.put(idAttribute.getText(), obj);
       path.removeHandler("property");
    }
}
   
PropertyHandler
privateclass PropertyHandler implements ElementHandler {
    Map<String, Field> mapField;
    Object obj;
 
    public PropertyHandler(Map<String, Field> mapField, Object obj) {
       this.mapField = mapField;
       this.obj = obj;
    }
 
    publicvoid .Start(ElementPath path) {
       Element propertyElement = path.getCurrent();
       Attribute nameAttribute = propertyElement.attribute("name");
       path.addHandler("value"new ValueHandler(mapFieldobj,
              nameAttribute));
       path.addHandler("list"new ListHandler(mapFieldobj,
              nameAttribute));
       path.addHandler("set"new SetHandler(mapFieldobj,
              nameAttribute));
       path.addHandler("map"new MapHandler(mapFieldobj,
              nameAttribute));
       path.addHandler("ref"new RefHandler(mapFieldobj,
              nameAttribute));
    }
 
    publicvoid .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設置它的值。
privatevoid setFieldValue(Object obj, Field field, String value) {
    String fieldType = field.getType().getSimpleName();
    try {
       if (fieldType.equals("int"))
           field.setInt(obj, new Integer(value));
       elseif (fieldType.equals("float"))
           field.setFloat(obj, new Float(value));
       elseif (fieldType.equals("boolean"))
           field.setBoolean(obj, new Boolean(value));
       elseif (fieldType.equals("char"))
           field.setChar(obj, value.charAt(0));
       elseif (fieldType.equals("double"))
           field.setDouble(obj, new Double(value));
       elseif (fieldType.equals("long"))
           field.setLong(obj, new Long(value));
       else
           field.set(obj, value);
    catch (IllegalArgumentException e) {
       e.printStackTrace();
    catch (IllegalAccessException e) {
       e.printStackTrace();
    }
}
 
privatevoid setFieldValue(Object obj, Field field, List<String> value) {
    try {
       field.set(obj, value);
    catch (IllegalArgumentException e) {
       e.printStackTrace();
    catch (IllegalAccessException e) {
       e.printStackTrace();
    }
}
 
5.測試
publicstaticvoid 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

本文出自 “子 孑” 博客,請務必保留此出處http://zhangjunhd.blog.51cto.com/113473/126545



這裏將模仿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;
 
publicclass Person {
    private String name;
    privateintage;
    privatefloatheight;
 
    public String getName() {returnname;}
    publicvoid setName(String name) {this.name = name;}
    publicint getAge() {returnage;}
    publicvoid setAge(int age) {this.age = age;}
    publicfloat getHeight() {returnheight;}
    publicvoid setHeight(float height) {this.height = height;}
}
緊接着,構建一個ListOne的實例myList
ListOne.java
package com.zj.ioc.di.imp;
import java.util.List;
 
publicclass ListOne {
    private List<String> msg;
 
    public List<String> getMsg() {returnmsg;}
    publicvoid setMsg(List<String> msg) {this.msg = msg;}
}
緊接着,構建一個SetOne的實例mySet
SetOne.java
package com.zj.ioc.di.imp;
import java.util.Set;
 
publicclass SetOne {
    private Set<String> msg;
 
    public Set<String> getMsg() {returnmsg;}
    publicvoid setMsg(Set<String> msg) {this.msg = msg;}
}
緊接着,構建一個MapOne的實例myMap
MapOne.java
package com.zj.ioc.di.imp;
import java.util.Map;
 
publicclass MapOne {
    private Map<String,String> msg;
 
    public Map<String, String> getMsg() {returnmsg;}
    publicvoid setMsg(Map<String, String> msg) {this.msg = msg;}
}
最後構建一個Persons類的實例us,其中包含meyou兩個已經構建好的對象:
Persons.java
package com.zj.ioc.di.imp;
 
publicclass Persons {
    private Person i;
    private Person u;
   
    public Person getI() {returni;}
    publicvoid setI(Person i) {this.i = i;}
    public Person getU() {returnu;}
    publicvoid 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對其處理。
publicvoid 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
privateclass BeanHandler implements ElementHandler {
    Object obj = null;
 
    publicvoid .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));
    }
 
    publicvoid .End(ElementPath path) {
       Element beanElement = path.getCurrent();
       Attribute idAttribute = beanElement.attribute("id");
       beanMap.put(idAttribute.getText(), obj);
       path.removeHandler("property");
    }
}
   
PropertyHandler
privateclass PropertyHandler implements ElementHandler {
    Map<String, Field> mapField;
    Object obj;
 
    public PropertyHandler(Map<String, Field> mapField, Object obj) {
       this.mapField = mapField;
       this.obj = obj;
    }
 
    publicvoid .Start(ElementPath path) {
       Element propertyElement = path.getCurrent();
       Attribute nameAttribute = propertyElement.attribute("name");
       path.addHandler("value"new ValueHandler(mapFieldobj,
              nameAttribute));
       path.addHandler("list"new ListHandler(mapFieldobj,
              nameAttribute));
       path.addHandler("set"new SetHandler(mapFieldobj,
              nameAttribute));
       path.addHandler("map"new MapHandler(mapFieldobj,
              nameAttribute));
       path.addHandler("ref"new RefHandler(mapFieldobj,
              nameAttribute));
    }
 
    publicvoid .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設置它的值。
privatevoid setFieldValue(Object obj, Field field, String value) {
    String fieldType = field.getType().getSimpleName();
    try {
       if (fieldType.equals("int"))
           field.setInt(obj, new Integer(value));
       elseif (fieldType.equals("float"))
           field.setFloat(obj, new Float(value));
       elseif (fieldType.equals("boolean"))
           field.setBoolean(obj, new Boolean(value));
       elseif (fieldType.equals("char"))
           field.setChar(obj, value.charAt(0));
       elseif (fieldType.equals("double"))
           field.setDouble(obj, new Double(value));
       elseif (fieldType.equals("long"))
           field.setLong(obj, new Long(value));
       else
           field.set(obj, value);
    catch (IllegalArgumentException e) {
       e.printStackTrace();
    catch (IllegalAccessException e) {
       e.printStackTrace();
    }
}
 
privatevoid setFieldValue(Object obj, Field field, List<String> value) {
    try {
       field.set(obj, value);
    catch (IllegalArgumentException e) {
       e.printStackTrace();
    catch (IllegalAccessException e) {
       e.printStackTrace();
    }
}
 
5.測試
publicstaticvoid 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

本文出自 “子 孑” 博客,請務必保留此出處http://zhangjunhd.blog.51cto.com/113473/126545


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