这里将模仿 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 msg ;

 

    public List getMsg() { return msg ;}

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

}

紧接着,构建一个 SetOne 的实例 mySet
SetOne.java
package com.zj.ioc.di.imp;

import java.util.Set;

 

public class SetOne {

    private Set msg ;

 

    public Set getMsg() { return msg ;}

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

}
紧接着,构建一个 MapOne 的实例 myMap
MapOne.java
package com.zj.ioc.di.imp;

import java.util.Map;

 

public class MapOne {

    private Map msg ;

 

    public Map getMsg() { return msg ;}

    public void setMsg(Map 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 beanMap = new HashMap();
……
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 mapField = new HashMap();

       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 mapField ;

    Object obj ;

 

    public PropertyHandler(Map 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 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