這裏將模仿Spring實現一種基於xml配置文件的依賴注入機制。文件中將實現3中注入,一是單值注入,包括int,float,double,char等,也包括String注入;二是Java容器注入,包括List,Set,Map三種容器的注入,最後一種是java
bean對象注入。
實現的機制是,使用Dom4j對xml配置文件進行解析,這裏使用dom4j的Element
Handler機制,一種類似與責任鏈模式的實現機制;對於java對象的構建使用反射機制,這裏主要是針對得到的類的Field進行set賦值。我試圖通過調用Method的invoke方法調用類本身的setter方法,但是由於通過xml解析得到的值都是String,如果將這些String動態的轉換爲相應的確定類型是個難點,Method的invoke方法,如果形參是int,而傳入java.lang.Integer,它不會認,所以嘗試失敗,只能通過Field的set方法傳入特定值。
配置文件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類的實例me和you:
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,其中包含me和you兩個已經構建好的對象:
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就是bean的id屬性,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.ElementHandler,dom4j的ElementHandler接口有兩個方法,一個是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(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));
}
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,float,double,char等,也包括String注入;二是Java容器注入,包括List,Set,Map三種容器的注入,最後一種是java
bean對象注入。
實現的機制是,使用Dom4j對xml配置文件進行解析,這裏使用dom4j的Element
Handler機制,一種類似與責任鏈模式的實現機制;對於java對象的構建使用反射機制,這裏主要是針對得到的類的Field進行set賦值。我試圖通過調用Method的invoke方法調用類本身的setter方法,但是由於通過xml解析得到的值都是String,如果將這些String動態的轉換爲相應的確定類型是個難點,Method的invoke方法,如果形參是int,而傳入java.lang.Integer,它不會認,所以嘗試失敗,只能通過Field的set方法傳入特定值。
配置文件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類的實例me和you:
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,其中包含me和you兩個已經構建好的對象:
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就是bean的id屬性,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.ElementHandler,dom4j的ElementHandler接口有兩個方法,一個是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(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));
}
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