spring ioc 模拟

 本文主要的内容就是用自己的代码实现spring下面的代码功能:

    InputStream is = new FileInputStream("bean.xml"); 
    XmlBeanFactory factory = new XmlBeanFactory(is); 
    Action action = (Action) factory.getBean("TheAction");
具体流程如下图:
 

 

 1. 确定有两个类,一个是Course,一个是Student,Course由名称、学分、描述组成。Student由学号、名字、课程组成。现在要先建一个Course然后把这个类作为Student的Course属性。

  
  
  
  
  1. //Course.java: 
  2. package entity; 
  3. public class Course { 
  4.     private String name; 
  5.     private long credit; 
  6.     private String desc; 
  7.      public Course() { 
  8.         super(); 
  9.     } 
  10.     public String getName() { 
  11.         return name; 
  12.     } 
  13.     public void setName(String name) { 
  14.         this.name = name; 
  15.     } 
  16.     public long getCredit() { 
  17.         return credit; 
  18.     } 
  19.     public void setCredit(long credit) { 
  20.         this.credit = credit; 
  21.     } 
  22.     public String getDesc() { 
  23.         return desc; 
  24.     } 
  25.     public void setDesc(String desc) { 
  26.         this.desc = desc; 
  27.     } 
  28.      
  29. }  

 

  
  
  
  
  1. //Student.java: 
  2. package entity; 
  3. public class Student { 
  4.     private String NO; 
  5.     private String name; 
  6.     private Course course; 
  7.     public String getNO() { 
  8.         return NO; 
  9.     } 
  10.     public void setNO(String nO) { 
  11.         NO = nO; 
  12.     } 
  13.     public String getName() { 
  14.         return name; 
  15.     } 
  16.     public void setName(String name) { 
  17.         this.name = name; 
  18.     } 
  19.     public Course getCourse() { 
  20.         return course; 
  21.     } 
  22.     public void setCourse(Course course) { 
  23.         this.course = course; 
  24.     } 
  25.      
  26. }  

 

2 在bean.xml中写上bean的信息,我改了一下xml的名字,现在是conf.xml,name和class都是必要的,而children节点的property就是这个bean的一些属性。property中的param指这个属性的名字,text的部分是value。
 
  
  
  
  
  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans> 
  3. <bean id="mathCourse" class="entity.Course"> 
  4.     <property param="name">math</property> 
  5.     <property param="credit">5</property> 
  6.     <property param="desc"> 
  7.         数学 
  8.     </property> 
  9. </bean> 
  10. <bean id="stud0" class="entity.Student"> 
  11.     <property param="NO">000</property> 
  12.     <property param="name">stud0</property> 
  13.     <property param="course" ref="mathCourse">mathCourse</property> 
  14. </bean> 
  15. </beans>  
xml里面的信息要和上面的类的属性相互对应,在property上写有ref的节点说明是根据上上面已经定义的bean注入进来的。
 

 

 

3.用一个Property类作为存放每个<property/>节点的信息,因为比较的简单,所以这个类只有几个属性
 
  
  
  
  
  1. package entity; 
  2. public class Property { 
  3.     private String name; 
  4.     private boolean ref; 
  5.     private String value; 
  6.     public String getName() { 
  7.         return name; 
  8.     } 
  9.     public void setName(String name) { 
  10.         this.name = name; 
  11.     } 
  12.     public boolean isRef() { 
  13.         return ref; 
  14.     } 
  15.     public void setRef(boolean ref) { 
  16.         this.ref = ref; 
  17.     } 
  18.     public String getValue() { 
  19.         return value; 
  20.     } 
  21.     public void setValue(String value) { 
  22.         this.value = value; 
  23.     } 

 

 

4.通过解析这个xml获得写在里面的信息。这里使用dom4j
 
  
  
  
  
  1. public static Map<String, Property> getBeanParams(Element bean) { 
  2.         Map<String, Property> map = new HashMap<String, Property>(); 
  3.         for (Iterator<Element> beanIt = bean.elementIterator(); beanIt 
  4.                 .hasNext();) { 
  5.             Element property = beanIt.next(); 
  6.             Property p = new Property(); 
  7.             p.setName(property.attribute("param").getStringValue()); 
  8.             p.setRef(property.attribute("ref") == null ? false : true); 
  9.             p.setValue(property.getTextTrim()); 
  10.             map.put(property.attribute("param").getStringValue(), p); 
  11.         } 
  12.         return map; 
  13.     }  

 

 

5.使用java的反射对对象的属性进行赋值。可以通过两种方法,一种是直接通过访问属性,另一种就是使用方法就是setXXX(value),当然也可以用构造函数,用起来不是一般的麻烦。
 
  
  
  
  
  1. package reflect; 
  2. import java.lang.reflect.Constructor; 
  3. import java.lang.reflect.Field; 
  4. import java.lang.reflect.InvocationTargetException; 
  5. import java.lang.reflect.Method; 
  6. import java.util.HashMap; 
  7. import java.util.Map;  
  8. public class ClassHelper { 
  9.     // 通过类方法获取属性值 
  10.      
  11. public static Map<String, Object> getMethods(Object obj) 
  12.             throws IllegalAccessException, IllegalArgumentException, 
  13.             InvocationTargetException { 
  14.         Map<String, Object> map = new HashMap<String, Object>(); 
  15.         Method[] method = obj.getClass().getDeclaredMethods(); 
  16.         for (int i = 0; i < method.length; i++) { 
  17.             String methodName = method[i].getName().toString(); 
  18.             if (methodName.startsWith("get")) { 
  19.                 map.put(method[i].getName().toString(), 
  20.                         method[i].invoke(obj, null)); 
  21.             } 
  22.         } 
  23.         return map; 
  24.     } 
  25.     // 通过类方法对属性赋值 
  26.     public static String[] setMethods(Object obj, 
  27.             Map<String, Property> propertyMap, Map<String, Object> objMap) 
  28.             throws NumberFormatException, IllegalAccessException, 
  29.             IllegalArgumentException, InvocationTargetException { 
  30.         Method[] method = obj.getClass().getDeclaredMethods(); 
  31.         String[] methods = new String[method.length]; 
  32.         for (int i = 0; i < method.length; i++) { 
  33.             String methodName = method[i].getName().toString(); 
  34.             if (methodName.startsWith("set")) { 
  35.                 for (Class<?> c : method[i].getParameterTypes()) { 
  36.                     String paramType = c.getSimpleName().toString();// 获取方法中变量的类型 
  37.                     String name = method[i].getName().toString() 
  38.                             .substring(3, methodName.length()).toLowerCase();// 记得要转换为小写,截取后得到的string开头字母是大写 
  39.                     // System.out.println(name); 
  40.                     Property property = propertyMap.get(name); 
  41.                     String val = property.getValue(); 
  42.                     if (property.isRef()) { 
  43.                         Object o = objMap.get(val); 
  44.                         method[i].invoke(obj, o); 
  45.                     } else if (paramType.toLowerCase().equals("long")) { 
  46.                         method[i].invoke(obj, Long.parseLong(val)); 
  47.                     } else if (paramType.toLowerCase().equals("int"
  48.                             || paramType.equals("Integer")) { 
  49.                         method[i].invoke(obj, Integer.valueOf(val)); 
  50.                     } else if (paramType.toLowerCase().equals("float")) { 
  51.                         method[i].invoke(obj, Float.valueOf(val)); 
  52.                     } else if (paramType.toLowerCase().equals("short")) { 
  53.                         method[i].invoke(obj, Short.valueOf(val)); 
  54.                     } else if (paramType.toLowerCase().equals("double")) { 
  55.                         method[i].invoke(obj, Double.valueOf(val)); 
  56.                     } else if (paramType.toLowerCase().equals("char")) { 
  57.                         method[i].invoke(obj, val.charAt(0)); 
  58.                     } else if (paramType.toLowerCase().equals("boolean")) { 
  59.                         method[i].invoke(obj, Boolean.valueOf(val)); 
  60.                     } else if (paramType.toLowerCase().equals("byte")) { 
  61.                         method[i].invoke(obj, val.getBytes()[0]); 
  62.                     } else { 
  63.                             method[i].invoke(obj, val); 
  64.                     } 
  65.                 } 
  66.             } 
  67.         } 
  68.         return methods; 
  69.     } 
  70.     // 获取类属性的值 
  71.     public static Map<String, Object> getFieldsValues(Object obj) 
  72.             throws IllegalArgumentException, IllegalAccessException { 
  73.         Field[] field = obj.getClass().getDeclaredFields(); 
  74.         Map<String, Object> map = new HashMap<String, Object>(); 
  75.         for (int i = 0; i < field.length; i++) { 
  76.             field[i].setAccessible(true); // 允许访问私有属性 
  77.             map.put(field[i].getName(), field[i].get(obj));// 使用属性的名称作为key 
  78.                                                             // ,属性的值作为value 
  79.         } 
  80.         return map; 
  81.     } 
  82.     // 通过属性直接赋值 
  83.     public static String[] setFields(Object obj, 
  84.             Map<String, Property> propertyMap, Map<String, Object> objMap) 
  85.             throws NumberFormatException, IllegalArgumentException, 
  86.             IllegalAccessException { 
  87.         Field[] field = obj.getClass().getDeclaredFields(); 
  88.         String[] fields = new String[field.length]; 
  89.         for (int i = 0; i < field.length; i++) { 
  90.             field[i].setAccessible(true); // 允许访问私有属性 
  91.             String name = field[i].getName(); 
  92.             fields[i] = name; 
  93.             String type = field[i].getType().getSimpleName(); 
  94.             // System.out.println("name:" + name + "   type:" + type); 
  95.             Property property = propertyMap.get(name); 
  96.             String val = property.getValue(); 
  97.             if (property.isRef()) { 
  98.                 Object o = objMap.get(val); 
  99.                 field[i].set(obj, o); 
  100.             } else if (type.toLowerCase().equals("long")) { 
  101.                 field[i].setLong(obj, Long.parseLong(val)); 
  102.             } else if (type.toLowerCase().equals("int"
  103.                     || type.equals("Integer")) { 
  104.                 field[i].setInt(obj, Integer.valueOf(val)); 
  105.             } else if (type.toLowerCase().equals("float")) { 
  106.                 field[i].setFloat(obj, Float.valueOf(val)); 
  107.             } else if (type.toLowerCase().equals("short")) { 
  108.                 field[i].setShort(obj, Short.valueOf(val)); 
  109.             } else if (type.toLowerCase().equals("double")) { 
  110.                 field[i].setDouble(obj, Double.valueOf(val)); 
  111.             } else if (type.toLowerCase().equals("char")) { 
  112.                 field[i].setChar(obj, val.charAt(0)); 
  113.             } else if (type.toLowerCase().equals("boolean")) { 
  114.                 field[i].setBoolean(obj, Boolean.valueOf(val)); 
  115.             } else if (type.toLowerCase().equals("byte")) { 
  116.                 field[i].setByte(obj, val.getBytes()[0]); 
  117.             } else { 
  118.                 // System.out.println(val); 
  119.                 field[i].set(obj, val); 
  120.             } 
  121.         } 
  122.         return fields; 
  123.     }  
  124.     /** 
  125.      * @param args 
  126.      */ 
  127.     public static void main(String[] args) { 
  128.         // TODO Auto-generated method stub 
  129.     } 
  130. }  

 

 

5.利用上面的方法构建BeanFactory;
 
  
  
  
  
  1. public class BeanFactory { 
  2.     /** 
  3.      * @param args 
  4.      */ 
  5.     private String path; 
  6.     public static Map<String, Object> map; 
  7.     public BeanFactory() { 
  8.         this("src/bean.xml"); 
  9.     } 
  10.     public BeanFactory(String path) { 
  11.         super(); 
  12.         this.path = path; 
  13.         init(); 
  14.     } 
  15.     private void init() { 
  16.         Document doc = null
  17.         map = new HashMap<String, Object>(); 
  18.         SAXReader reader = new SAXReader(); 
  19.         try { 
  20.             doc = reader.read(new File(path)); 
  21.             Element root = doc.getRootElement(); 
  22.             for (Iterator<Element> beans = root.elementIterator(); beans 
  23.                     .hasNext();) { 
  24.                 Element bean = beans.next(); 
  25.                 Map<String, String> beanParams = XmlHelper.getBeanParams(bean); 
  26.                 Class cla = Class.forName(bean.attributeValue("class")); 
  27.                 Object obj = cla.newInstance(); 
  28.                 // set value 
  29.                 ClassHelper.setFields(obj, beanParams, map); 
  30.                 // ClassHelper.setMethods(obj, beanParams, map); 
  31.                 map.put(bean.attributeValue("name"), obj); 
  32.             } 
  33.         } catch (Exception e) { 
  34.             // TODO Auto-generated catch block 
  35.             e.printStackTrace(); 
  36.         } 
  37.         // System.out.println(System.getProperty("user.dir")); 
  38.     } 
  39.     public static <T> T getBean(String key, Class<T> classOf) { 
  40.         return (T) map.get(key); 
  41.     } 
  42.    
  43.     public String getPath() { 
  44.         return path; 
  45.     } 
  46.     public void setPath(String path) { 
  47.         this.path = path; 
  48.     }  

 

 

本次实现是通过直接访问类的属性进行赋值的。
6.写个main函数作为测试;
 
  
  
  
  
  1. public class Main { 
  2.     /** 
  3.      * @param args 
  4.      * @throws InvocationTargetException 
  5.      * @throws IllegalArgumentException 
  6.      * @throws IllegalAccessException 
  7.      */ 
  8.     public static void main(String[] args) throws IllegalAccessException, 
  9.             IllegalArgumentException, InvocationTargetException { 
  10.         // TODO Auto-generated method stub 
  11.         BeanFactory beanFactory = new BeanFactory("src/conf.xml"); 
  12.         Student stud0 = BeanFactory.getBean("stud0", Student.class); 
  13.         Course mathCourse = BeanFactory.getBean("mathCourse", Course.class); 
  14.         System.out.println("stud name:" + stud0.getName()); 
  15.         System.out.println("stud NO.:" + stud0.getNO()); 
  16.         Course testMathCourse = stud0.getCourse(); 
  17.         System.out.println("the same ?:" 
  18.                 + (mathCourse == testMathCourse ? true : false)); 
  19.         System.out.println("math name:" + mathCourse.getName()); 
  20.         System.out.println("math credit:" + mathCourse.getCredit()); 
  21.         System.out.println("math desc:" + mathCourse.getDesc()); 
  22.         Map<String, Object> vals = ClassHelper.getMethods(stud0); 
  23.         for (Iterator<String> it = vals.keySet().iterator(); it.hasNext();) { 
  24.             String key=it.next(); 
  25.             System.out.println(key+":"+vals.get(key)); 
  26.         } 
  27.     } 
  28. }  

 

 

7.运行结果;
stud name:stud0
stud NO.:000
the same ?:true
math name:math
math credit:5
math desc:数学
getNO:000
getCourse:entity.Course@db95a1
getName:stud0
通过第三行的输出可以看出来,stud0的Course和从BeanFactory拿出来的是同一个对象。其他的值和xml设置的值是一个样的。
 InputStream is =  new FileInputStream( "bean.xml"); 
    XmlBeanFactory factory = new XmlBeanFactory(is); 
BeanFactory beanFactory = new BeanFactory("src/conf.xml");此句和上面的两句功能一样
Action action = (Action) factory.getBean("TheAction");
Student stud0 = BeanFactory.getBean("stud0", Student.class);此 句和上一句功能一样。
在此目的达成。
done.

 

source code url:

https://github.com/scalaview/reflection

 

你可能感兴趣的:(java,spring,reflection)