Java代码实现依赖注入



这里将模仿 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 ;
     privateint age ;
     privatefloat height ;
 
     public  String getName() { return name ;}
     publicvoid  setName(String name) { this . name  = name;}
     publicint  getAge() { return age ;}
     publicvoid  setAge( int  age) { this . age  = age;}
     publicfloat  getHeight() { return height ;}
     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() { return msg ;}
     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() { return msg ;}
     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() { return msg ;}
     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() { return i ;}
     publicvoid  setI(Person i) { this . i  = i;}
     public  Person getU() { return u ;}
     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 ;
     privateint age ;
     privatefloat height ;
 
     public  String getName() { return name ;}
     publicvoid  setName(String name) { this . name  = name;}
     publicint  getAge() { return age ;}
     publicvoid  setAge( int  age) { this . age  = age;}
     publicfloat  getHeight() { return height ;}
     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() { return msg ;}
     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() { return msg ;}
     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() { return msg ;}
     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() { return i ;}
     publicvoid  setI(Person i) { this . i  = i;}
     public  Person getU() { return u ;}
     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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值