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属性。

Course.java

package entity;  
public class Course {  
    private String name;  
    private long credit;  
    private String desc;  
     public Course() {  
        super();  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public long getCredit() {  
        return credit;  
    }  
    public void setCredit(long credit) {  
        this.credit = credit;  
    }  
    public String getDesc() {  
        return desc;  
    }  
    public void setDesc(String desc) {  
        this.desc = desc;  
    }  
      
}   


//Student.java:  
package entity;  
public class Student {  
    private String NO;  
    private String name;  
    private Course course;  
    public String getNO() {  
        return NO;  
    }  
    public void setNO(String nO) {  
        NO = nO;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public Course getCourse() {  
        return course;  
    }  
    public void setCourse(Course course) {  
        this.course = course;  
    }  
      
}  


2 在bean.xml中写上bean的信息,我改了一下xml的名字,现在是conf.xml,name和class都是必要的,而children节点的property就是这个bean的一些属性。property中的param指这个属性的名字,text的部分是value。


<?xml version="1.0" encoding="UTF-8"?>  
<beans>  
<bean id="mathCourse" class="entity.Course">  
    <property param="name">math</property>  
    <property param="credit">5</property>  
    <property param="desc">  
        数学  
    </property>  
</bean>  
<bean id="stud0" class="entity.Student">  
    <property param="NO">000</property>  
    <property param="name">stud0</property>  
    <property param="course" ref="mathCourse">mathCourse</property>  
</bean>  
</beans>


xml里面的信息要和上面的类的属性相互对应,在property上写有ref的节点说明是根据上上面已经定义的bean注入进来的。
 
3.用一个Property类作为存放每个<property/>节点的信息,因为比较的简单,所以这个类只有几个属性
 
package entity;  
public class Property {  
    private String name;  
    private boolean ref;  
    private String value;  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public boolean isRef() {  
        return ref;  
    }  
    public void setRef(boolean ref) {  
        this.ref = ref;  
    }  
    public String getValue() {  
        return value;  
    }  
    public void setValue(String value) {  
        this.value = value;  
    }  
} 

4.通过解析这个xml获得写在里面的信息。这里使用dom4j

public static Map<String, Property> getBeanParams(Element bean) {  
        Map<String, Property> map = new HashMap<String, Property>();  
        for (Iterator<Element> beanIt = bean.elementIterator(); beanIt  
                .hasNext();) {  
            Element property = beanIt.next();  
            Property p = new Property();  
            p.setName(property.attribute("param").getStringValue());  
            p.setRef(property.attribute("ref") == null ? false : true);  
            p.setValue(property.getTextTrim());  
            map.put(property.attribute("param").getStringValue(), p);  
        }  
        return map;  
    }

 5.使用java的反射对对象的属性进行赋值。可以通过两种方法,一种是直接通过访问属性,另一种就是使用方法就是setXXX(value),当然也可以用构造函数,用起来不是一般的麻烦。

package reflect;  
import java.lang.reflect.Constructor;  
import java.lang.reflect.Field;  
import java.lang.reflect.InvocationTargetException;  
import java.lang.reflect.Method;  
import java.util.HashMap;  
import java.util.Map;   
public class ClassHelper {  
    // 通过类方法获取属性值  
      
public static Map<String, Object> getMethods(Object obj)  
            throws IllegalAccessException, IllegalArgumentException,  
            InvocationTargetException {  
        Map<String, Object> map = new HashMap<String, Object>();  
        Method[] method = obj.getClass().getDeclaredMethods();  
        for (int i = 0; i < method.length; i++) {  
            String methodName = method[i].getName().toString();  
            if (methodName.startsWith("get")) {  
                map.put(method[i].getName().toString(),  
                        method[i].invoke(obj, null));  
            }  
        }  
        return map;  
    }  
    // 通过类方法对属性赋值  
    public static String[] setMethods(Object obj,  
            Map<String, Property> propertyMap, Map<String, Object> objMap)  
            throws NumberFormatException, IllegalAccessException,  
            IllegalArgumentException, InvocationTargetException {  
        Method[] method = obj.getClass().getDeclaredMethods();  
        String[] methods = new String[method.length];  
        for (int i = 0; i < method.length; i++) {  
            String methodName = method[i].getName().toString();  
            if (methodName.startsWith("set")) {  
                for (Class<?> c : method[i].getParameterTypes()) {  
                    String paramType = c.getSimpleName().toString();// 获取方法中变量的类型  
                    String name = method[i].getName().toString()  
                            .substring(3, methodName.length()).toLowerCase();// 记得要转换为小写,截取后得到的string开头字母是大写  
                    // System.out.println(name);  
                    Property property = propertyMap.get(name);  
                    String val = property.getValue();  
                    if (property.isRef()) {  
                        Object o = objMap.get(val);  
                        method[i].invoke(obj, o);  
                    } else if (paramType.toLowerCase().equals("long")) {  
                        method[i].invoke(obj, Long.parseLong(val));  
                    } else if (paramType.toLowerCase().equals("int")  
                            || paramType.equals("Integer")) {  
                        method[i].invoke(obj, Integer.valueOf(val));  
                    } else if (paramType.toLowerCase().equals("float")) {  
                        method[i].invoke(obj, Float.valueOf(val));  
                    } else if (paramType.toLowerCase().equals("short")) {  
                        method[i].invoke(obj, Short.valueOf(val));  
                    } else if (paramType.toLowerCase().equals("double")) {  
                        method[i].invoke(obj, Double.valueOf(val));  
                    } else if (paramType.toLowerCase().equals("char")) {  
                        method[i].invoke(obj, val.charAt(0));  
                    } else if (paramType.toLowerCase().equals("boolean")) {  
                        method[i].invoke(obj, Boolean.valueOf(val));  
                    } else if (paramType.toLowerCase().equals("byte")) {  
                        method[i].invoke(obj, val.getBytes()[0]);  
                    } else {  
                            method[i].invoke(obj, val);  
                    }  
                }  
            }  
        }  
        return methods;  
    }  
    // 获取类属性的值  
    public static Map<String, Object> getFieldsValues(Object obj)  
            throws IllegalArgumentException, IllegalAccessException {  
        Field[] field = obj.getClass().getDeclaredFields();  
        Map<String, Object> map = new HashMap<String, Object>();  
        for (int i = 0; i < field.length; i++) {  
            field[i].setAccessible(true); // 允许访问私有属性  
            map.put(field[i].getName(), field[i].get(obj));// 使用属性的名称作为key  
                                                            // ,属性的值作为value  
        }  
        return map;  
    }  
    // 通过属性直接赋值  
    public static String[] setFields(Object obj,  
            Map<String, Property> propertyMap, Map<String, Object> objMap)  
            throws NumberFormatException, IllegalArgumentException,  
            IllegalAccessException {  
        Field[] field = obj.getClass().getDeclaredFields();  
        String[] fields = new String[field.length];  
        for (int i = 0; i < field.length; i++) {  
            field[i].setAccessible(true); // 允许访问私有属性  
            String name = field[i].getName();  
            fields[i] = name;  
            String type = field[i].getType().getSimpleName();  
            // System.out.println("name:" + name + "   type:" + type);  
            Property property = propertyMap.get(name);  
            String val = property.getValue();  
            if (property.isRef()) {  
                Object o = objMap.get(val);  
                field[i].set(obj, o);  
            } else if (type.toLowerCase().equals("long")) {  
                field[i].setLong(obj, Long.parseLong(val));  
            } else if (type.toLowerCase().equals("int")  
                    || type.equals("Integer")) {  
                field[i].setInt(obj, Integer.valueOf(val));  
            } else if (type.toLowerCase().equals("float")) {  
                field[i].setFloat(obj, Float.valueOf(val));  
            } else if (type.toLowerCase().equals("short")) {  
                field[i].setShort(obj, Short.valueOf(val));  
            } else if (type.toLowerCase().equals("double")) {  
                field[i].setDouble(obj, Double.valueOf(val));  
            } else if (type.toLowerCase().equals("char")) {  
                field[i].setChar(obj, val.charAt(0));  
            } else if (type.toLowerCase().equals("boolean")) {  
                field[i].setBoolean(obj, Boolean.valueOf(val));  
            } else if (type.toLowerCase().equals("byte")) {  
                field[i].setByte(obj, val.getBytes()[0]);  
            } else {  
                // System.out.println(val);  
                field[i].set(obj, val);  
            }  
        }  
        return fields;  
    }   
    /**  
     * @param args  
     */  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
    }  
}  
 6.利用上面的方法构建BeanFactory;
public class BeanFactory {  
    /**  
     * @param args  
     */  
    private String path;  
    public static Map<String, Object> map;  
    public BeanFactory() {  
        this("src/bean.xml");  
    }  
    public BeanFactory(String path) {  
        super();  
        this.path = path;  
        init();  
    }  
    private void init() {  
        Document doc = null;  
        map = new HashMap<String, Object>();  
        SAXReader reader = new SAXReader();  
        try {  
            doc = reader.read(new File(path));  
            Element root = doc.getRootElement();  
            for (Iterator<Element> beans = root.elementIterator(); beans  
                    .hasNext();) {  
                Element bean = beans.next();  
                Map<String, String> beanParams = XmlHelper.getBeanParams(bean);  
                Class cla = Class.forName(bean.attributeValue("class"));  
                Object obj = cla.newInstance();  
                // set value  
                ClassHelper.setFields(obj, beanParams, map);  
                // ClassHelper.setMethods(obj, beanParams, map);  
                map.put(bean.attributeValue("name"), obj);  
            }  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
        // System.out.println(System.getProperty("user.dir"));  
    }  
    public static <T> T getBean(String key, Class<T> classOf) {  
        return (T) map.get(key);  
    }  
    
    public String getPath() {  
        return path;  
    }  
    public void setPath(String path) {  
        this.path = path;  
    }   
}  

本次实现是通过直接访问类的属性进行赋值的。

7.写个main函数作为测试;
public class Main {  
    /**  
     * @param args  
     * @throws InvocationTargetException  
     * @throws IllegalArgumentException  
     * @throws IllegalAccessException  
     */  
    public static void main(String[] args) throws IllegalAccessException,  
            IllegalArgumentException, InvocationTargetException {  
        // TODO Auto-generated method stub  
        BeanFactory beanFactory = new BeanFactory("src/conf.xml");  
        Student stud0 = BeanFactory.getBean("stud0", Student.class);  
        Course mathCourse = BeanFactory.getBean("mathCourse", Course.class);  
        System.out.println("stud name:" + stud0.getName());  
        System.out.println("stud NO.:" + stud0.getNO());  
        Course testMathCourse = stud0.getCourse();  
        System.out.println("the same ?:"  
                + (mathCourse == testMathCourse ? true : false));  
        System.out.println("math name:" + mathCourse.getName());  
        System.out.println("math credit:" + mathCourse.getCredit());  
        System.out.println("math desc:" + mathCourse.getDesc());  
        Map<String, Object> vals = ClassHelper.getMethods(stud0);  
        for (Iterator<String> it = vals.keySet().iterator(); it.hasNext();) {  
            String key=it.next();  
            System.out.println(key+":"+vals.get(key));  
        }  
    }  
}   

8.运行结果;

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)