这里将模仿 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<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 ,其中包含 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<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.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<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