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

来源:互联网 发布:sql server2008 下载 编辑:程序博客网 时间:2024/06/06 01:28

      作为一个学习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的解耦,在代码不变的情况下,执行不同的逻辑。

 

 

 

 

 

 

 

 

 

 

 

 

 

0 0
原创粉丝点击