这里将模仿
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;
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
public
List
public
void
setMsg(List
}
|
紧接着,构建一个
SetOne
的实例
mySet
:
SetOne.java
package
com.zj.ioc.di.imp;
import
java.util.Set;
public
class
SetOne {
private
Set
public
Set
public
void
setMsg(Set
}
|
紧接着,构建一个
MapOne
的实例
myMap
:
MapOne.java
package
com.zj.ioc.di.imp;
import
java.util.Map;
public
class
MapOne {
private
Map
public
Map
public
void
setMsg(Map
}
|
最后构建一个
Persons
类的实例
us
,其中包含
me
和
you
两个已经构建好的对象:
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
就是
bean
的
id
属性,
value
就是这个对象;
private
Map
……
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.ElementHandler
,
dom4j
的
ElementHandler
接口有两个方法,一个是
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
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
Object
obj
;
public
PropertyHandler(Map
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
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