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

Java代码实现依赖注入的更多相关文章

  1. 在ABAP里模拟实现Java Spring的依赖注入

    Dependency Injection- 依赖注入,在Java Spring框架中有着广泛地应用.通过依赖注入,我们不必在应用代码里繁琐地初始化依赖的资源,非常方便. 那么ABAP能否从语言层面上也 ...

  2. Java Spring各种依赖注入注解的区别

    Spring对于Bean的依赖注入,支持多种注解方式: @Resource javax.annotation JSR250 (Common Annotations for Java) @Inject ...

  3. JAVA框架 Spring 依赖注入

    一:介绍 情景:我们在给程序分层的时候:web层.业务层.持久层,各个层之间会有依赖.比如说:业务层和持久层,业务层的代码在调用持久层的时候,传统方式:new 持久层类. 进而进行调用,这种方式会导致 ...

  4. 详解Java Spring各种依赖注入注解的区别

    注解注入顾名思义就是通过注解来实现注入,Spring和注入相关的常见注解有Autowired.Resource.Qualifier.Service.Controller.Repository.Comp ...

  5. 【Java】 Spring依赖注入小试牛刀:编写第一个Spring ApplicationContext Demo

    0  Spring的依赖注入大致是这样工作的: 将对象如何构造(ID是什么?是什么类型?给属性设置什么值?给构造函数传入什么值?)写入外部XML文件里.在调用者需要调用某个类时,不自行构造该类的对象, ...

  6. Effective Java —— 优先考虑依赖注入来引用资源

    本文参考 本篇文章参考自<Effective Java>第三版第五条"Prefer dependency injection to hardwiring resources&qu ...

  7. [原创]20行ruby代码实现依赖注入框架

    我需要依赖注入 业余时间开发的娱乐项目 (为了练习使用ruby语言) 遵循SRP原则,业务逻辑拆分由各个service类型提供,假设存在如下几个类型 GameService 封装主要游戏业务逻辑 Us ...

  8. Java反射及依赖注入简单模拟

    一.编写Dao类 ? 1 2 3 4 5 6 7 8 9 10 11 package cn.com.songjy.annotation;   import java.util.Date;   publ ...

  9. [Android]使用Dagger 2进行依赖注入 - Producers(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6234811.html 使用Dagger 2进行依赖注入 - P ...

随机推荐

  1. 64位win10系统无法安装.Net framework3.5的两种解决方法

    参考网站: https://blog.csdn.net/zang141588761/article/details/52177290 在Windows10中,当我们安装某些软件的时候会提示“你的电脑上 ...

  2. 35. oracle中instr在平台上的转换用法

    //INSTR('15,17,29,3,30,4',a.femployee) var instrSql = fun.funHelper.charIndex('a.femployee',"'& ...

  3. myeclipse2016-ci破解疑难杂症问题整理

    感谢网上的各位大神,在你们的基础,我又整理了下安装成功的心得,破解不成功时一定注意下红色字体内容,避免被坑,都是教训. 试了网上N种破解工具+方法,Myeclipse 2016装了很多遍(本人官网下载 ...

  4. html的基本数据类型(数字,字符串, 列表, 字典)

    基本数据类型 1. 数字 a = 18 ; 2. 字符串 a = 'alex'a.chartAt(索引位置)a.substring(起始位置, 借宿位置)a.length 获取当前字符串长度a.tri ...

  5. 回调(CallBack)

    又名钩子函数(C语言里Hook) 不知道如何实现,可以写个回调, 相当于提供个钩子,让别人来挂东西,来实现. 其实就是用多态,实现了分离 . package cn.bjsxt.oop.callback ...

  6. 【Java】JavaIO(二)、节点流

    一.InputStream & outputStream Java字节流主要是以InputStream (输入流),outputStream(输出流)为基类,本身是抽象类不能创建实例,但是是字 ...

  7. express中使用ejs

    [express中使用ejs] 1.添加 ejs 依赖. npm install ejs --save 2.设置 view engine 为 ejs 即可.

  8. 正向工程configuration配置连接

    在执行正向工程的时候需要用到这个关键词里面的configure();方法, 这个方法有好几个重构, 都是参数不一样的, 也可以空着不写, 不写的话就会默认去找hibernate.cfg.xml这个文件 ...

  9. SpringCloud 简单理解

    0.SpringCloud,微服务架构.包括 服务发现(Eureka),断路器(Hystrix),服务网关(Zuul),客户端负载均衡(Ribbon).服务跟踪(Sleuth).消息总线(Bus).消 ...

  10. codeblocks c++11 pthread

    支持c++11: setting->compiler-> 打上勾即可.(如果没有c++11,那么请更新codeblocks最新版.) pthread_create错误: 由于pthread ...