自己实现Spring加载xml配置文件

把代理和反射系统学完后,突然想自己实现一下spring是如何加载xml配置文件的,当然这里要用到反射。Spring 通过 XML 配置模式装载 Bean 的过程:

  1. 将程序内所有 XML 或 Properties 配置文件加载入内存中
  2. Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息
  3. 使用反射机制,根据这个字符串获得某个类的Class实例
  4. 动态配置实例的属性
这样做的好处是:
  1. 不用每一次都要在代码里面去new或者做其他的事情
  2. 以后要改的话直接改配置文件,代码维护起来就很方便了
  3. 有时为了适应某些需求,Java类里面不一定能直接调用另外的方法,可以通过反射机制来实现

那我们开始吧

1.准备工作

1) Maven+Idea
2) Dom4j解析xml

2.创建Person实体

package com.cxx.reflect;

/**
 * @Author: cxx
 * @Date: 2018/6/1 10:23
 */
public class Person {
    private String name;
    public int age;
    private  int score;

    public Person(){ }
    public Person(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
}

3.在resources下建立spring.xml

自己实现Spring加载xml配置文件_第1张图片


<beans>
    <bean id="people" class="com.cxx.reflect.Person">
        <property name="name" value="cxx"/>
        <property name="age" value="20"/>
        <property name="score" value="88"/>
    bean>
beans>

4.编写SpringBeanFactory

package com.cxx.reflect;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @Author: cxx
 * 模拟spring 加载xml配置文件(dom4j)
 * @Date: 2018/6/1 16:38
 */
public class SpringBeanFactory {
    //初始化的bean全用map集合保存
    private static Map beanMap = new HashMap<>();

    public static void main(String[] args) {
        init("spring.xml");
        Person person = (Person) beanMap.get("people");
        System.out.println(person.toString());
    }
    /**
     * bean工厂初始化
     * @param xml
     */
    public static void init(String xml){
        try {
            SAXReader reader = new SAXReader();
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            //从class目录下获取指定的xml
            InputStream is = classLoader.getResourceAsStream(xml);
            Document doc = reader.read(is);
            Element rootElement = doc.getRootElement();
            //遍历bean
            Element foo;
            for (Iterator i =rootElement.elementIterator("bean");i.hasNext();){
                foo = (Element) i.next();
                //获取id和class
                Attribute id = foo.attribute("id");
                Attribute aClass = foo.attribute("class");
                //利用反射机制获取Class对象
                Class bean = Class.forName(aClass.getText());
                //获取class信息
                BeanInfo info = Introspector.getBeanInfo(bean);
                //获取其属性描述
                PropertyDescriptor pd[] = info.getPropertyDescriptors();
                //设置方法
                Method mSet = null;
                //创建一个对象
                Object obj = bean.newInstance();
                //遍历该bean的property属性
                for (Iterator ite = foo.elementIterator("property");ite.hasNext();){
                    Element foo2 = (Element) ite.next();
                    //获取name的属性
                    Attribute name = foo2.attribute("name");
                    //获取value值
                    Attribute value = foo2.attribute("value");
                    for (PropertyDescriptor pp : pd) {
                        if (pp.getName().equalsIgnoreCase(name.getText())){
                            mSet = pp.getWriteMethod();
                            Class[] types = mSet.getParameterTypes();
                            for (Class type : types) {
                                if (type.getName().equals("int")){
                                    //转换为整型
                                    mSet.invoke(obj,Integer.parseInt(value.getText()));
                                }else {
                                    //利用java反射调用set方法
                                    mSet.invoke(obj,value.getText());
                                }
                            }

                        }
                    }
                }
                beanMap.put(id.getText(),obj);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5.结果

自己实现Spring加载xml配置文件_第2张图片

总结

还要很多地方可以继续完善,行内有一句这样的老话:反射机制是Java框架的基石。一般应用层面很少用,不过这种东西,现在很多开源框架基本都已经封装好了,自己基本用不着写,不过了解一下还是不错的,其实也很容易理解。

你可能感兴趣的:(后端编程)