您的位置:首页 > 其它

自己写的一个简单的IOC容器

2014-08-14 21:35 417 查看
      作为一个学习JAVA只有4个月的同学,我能深切的理解初次接触Spring框架产生的困惑,也同样有探索SpringIOC容器的实现方式的冲动。我觉得IOC的那种将控制转交给容器的方式,配合上java接口,简直是太完美了,能有效的实现对象之间的解耦。于是,我经过自己的努力,自己写了一个IOC容器。

      这个容器是模仿SpringIOC容器写的,操作什么的都非常的相似。同样是通过读取配置文件中的内容来实现注入的。解析配置的XML文件是采用SAX方式,实现注入是采用反射技术。以下是所有的代码:

       首先,我建立3个接口,分别控制容器,bean元素,property元素

容器:

 import java.util.List;

/**

 * IOC容器接口

 * */

public interface IocContainer {

 /**

  * 用于启动IOC容器,根据配置文件完成对容器中所有bean的注册

  * */

 public void startIocContainer(String config);

 /**

  * 用于根据bean对象的id获得IOC容器中的bean的class属性所指向的对象

  * */

 public Object beanToObject(String id);

}

 

Bean:

import org.dom4j.Element;

public interface IocBean {

 /**

  * 根据配置文件的bean元素为当前bean对象赋值

  * */

 public void configToBean(Element bean);

}

 

Property:

import org.dom4j.Element;

public interface IocProperty {

 /**

  * 根据配置文件的bean元素下的property元素为当前property对象赋值

  * */

 public void configToProperty(Element property);

}

然后,根据这三个接口写出对应的三个实现类,其中容器的实现类较为复杂,Object beanToObject方法用到了反射。

容器:

import interfaceIOC.IocContainer;

import java.io.File;

import java.lang.reflect.Method;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.Set;

import org.dom4j.Document;

import org.dom4j.DocumentException;

import org.dom4j.Element;

import org.dom4j.io.SAXReader;

import testEntity.Dao;

public class WizardIocContainer implements IocContainer {

 private Map<String,WizardIocBean> beanMap;

 /**

  * @param config 需要传入配置文件的绝对路径

  * */

 public void startIocContainer(String config) {

  //访问配置文件

  File file=new File(config);

  //用SAX方式解析XML配置文件

  SAXReader reader=new SAXReader();

  try {

   Document doc=reader.read(file);

   Element root=doc.getRootElement();

   List<Element> eles=root.elements("bean");

   //对所有bean元素进行遍历,保存其id属性值到beanMap中

   //System.out.println(eles.size());

   Map<String,WizardIocBean> bMap=new HashMap<String,WizardIocBean>();

   for(Element ele:eles){

    

    WizardIocBean bean=new WizardIocBean();

    bean.configToBean(ele);

    bMap.put(bean.getId(),bean);

   }

   beanMap=bMap;

  } catch (DocumentException e) {

   e.printStackTrace();

  }

  

 }

 public Object beanToObject(String id){

  if(beanMap==null){

   System.out.println("请先启动Ioc容器");

   return null;

  }else{

   //根据id获得bean对象

   WizardIocBean bean=beanMap.get(id);

   //获得class属性中类名

   String className=bean.getClassName();

   //利用反射动态生成对象

   try{

    Class cls=Class.forName(className);

    Object obj=cls.newInstance();

    //为对象注入property中的值

     //获取该bean中的说有property内容

    Map<String,WizardIocProperty> propertyMap=bean.getPropertyMap();

     //若没有property内容,直接返回obj

    if(propertyMap==null){

     return obj;

    }

    //对其进行遍历

    Set<String> propertyNames=propertyMap.keySet();

    for(String propertyName:propertyNames){

     //获取对应的property

     WizardIocProperty property=propertyMap.get(propertyName);

     //若ref为空,直接执行对应的set方法就可以完成对obj对象的注入

     if(property.getRef()==null){

      //获得要注入的值

      String value=property.getValue();

      //拼凑出对应set方法的方法名

      String setName="set"+property.getName().toLowerCase()

           .substring(0, 1).toUpperCase()+

            property.getName()

            .toLowerCase().substring(1);

      //System.out.println(setName);

      //执行set方法,为对象赋值

      try{

       Method methodSet=cls.getMethod(setName, String.class);

       methodSet.invoke(obj, property.getValue());

      }catch(Exception e){

       e.printStackTrace();

      }

     }else{

      //获得ref中的值,这个值对应某一bean的id

      String ref=property.getRef();

      Class cls1=Class.forName(beanMap.get(ref).getClassName());

      String setName1="set"+property.getName().toLowerCase()

        .substring(0, 1).toUpperCase()+

         property.getName()

          .toLowerCase().substring(1);

      try{

       Class paramType=null;

       Method[] methods=cls.getMethods();

       for(Method m:methods){

        

        //System.out.println(m.getName());

        if(setName1.equals(m.getName())){

         Class<?>[] paramTypes=m.getParameterTypes();

         paramType=paramTypes[0];

         Method methodSet=cls.getMethod(setName1,paramType);

         Object obj1=cls1.newInstance();

         methodSet.invoke(obj, obj1);

        }

       }

       

      }catch(Exception e){

       e.printStackTrace();

      }

      

      

     }

    }

    return obj;

   }catch(Exception e){

    e.printStackTrace();

    return null;

     

   }

   

  }

  

  

 }

 

 

 

 

Bean:

import interfaceIOC.IocBean;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.dom4j.Element;

public class WizardIocBean implements IocBean{

 private String id;

 private String className;

 private Map<String,WizardIocProperty> propertyMap;

 public void configToBean(Element bean) {

  id=bean.attributeValue("id");

  className=bean.attributeValue("class");

  List<Element> eles=bean.elements("property");

  Map<String,WizardIocProperty> pMap=new HashMap<String,WizardIocProperty>();

  for(Element ele:eles){

   WizardIocProperty property=new WizardIocProperty();

   property.configToProperty(ele);

   pMap.put(property.getName(), property);

  }

  propertyMap=pMap;

 }

 public String getId() {

  return id;

 }

 public void setId(String id) {

  this.id = id;

 }

 public String getClassName() {

  return className;

 }

 public void setClassName(String className) {

  this.className = className;

 }

 public Map<String, WizardIocProperty> getPropertyMap() {

  return propertyMap;

 }

 public void setPropertyMap(Map<String, WizardIocProperty> propertyMap) {

  this.propertyMap = propertyMap;

 }

 

}

 

Property:

import org.dom4j.Element;

import interfaceIOC.IocProperty;

public class WizardIocProperty implements IocProperty {

 private String name;

 private String value;

 private String ref;

 public void configToProperty(Element property) {

  name=property.attributeValue("name");

  value=property.attributeValue("value");

  ref=property.attributeValue("ref");

 }

 public String getName() {

  return name;

 }

 public void setName(String name) {

  this.name = name;

 }

 public String getValue() {

  return value;

 }

 public void setValue(String value) {

  this.value = value;

 }

 public String getRef() {

  return ref;

 }

 public void setRef(String ref) {

  this.ref = ref;

 }

 

}

 

      下面写配置文件,做一个测试

<?xml version="1.0" encoding="UTF-8"?>

<beans>

 <bean id="jdbcdao" class="testEntity.JdbcDao"></bean>

 <bean id="myBatisdao" class="testEntity.MyBatisDao"></bean>

 <bean id="testDao" class="testEntity.TestController">

  <property name="where" value="这里"></property>

  <property name="dao" ref="myBatisdao"></property>

 </bean>

</beans>

 

 

测试类:

Dao接口:

public interface Dao {

 public void excute();

}

JDBCDao实现类

public class JdbcDao implements Dao {

 public void excute(){

  System.out.println("JdbcDao方式");

 }

}

MyBatisDao实现类

public class MyBatisDao implements Dao {

 public void excute(){

  System.out.println("MyBatisDao方式");

 }

}

 

 

TestController(为其分别注入dao 和 where)

public class TestController {

 private Dao dao;

 private String where;

 

 

 public Dao getDao() {

  return dao;

 }

 public void setDao(Dao dao) {

  this.dao = dao;

 }

 public String getWhere() {

  return where;

 }

 public void setWhere(String where) {

  this.where = where;

 }

 public void excute(){

  System.out.println(where);

  dao.excute();

 }

}

 

最后测试:

 

public class TestWizardSet {

 public static void main(String[] args) {

  String config="src/WizardIocContainerConfig.xml";

  WizardIocContainer wic=new WizardIocContainer();

  wic.startIocContainer(config);

  TestValue tv=(TestValue)wic.beanToObject("testValue");

  tv.excute();

 }

}

        当在配置中为dao注入不同的类是,如注入jdbcDao则执行jdbcDao中的excute方法,注入mybatisDao这执行mybatisDao中的excute方法,这样就可以实现dao的解耦,在代码不变的情况下,执行不同的逻辑。

 

 

 

 

 

 

 

 

 

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: