zoukankan      html  css  js  c++  java
  • 采用dom4j和反射模拟Spring框架的依赖注入功能

      Spring的依赖注入是指将对象的创建权交给Spring框架,将对象所依赖的属性注入进来的行为.在学习了dom4j后,其实也可以利用dom4j和反射做一个小Demo模拟Spring框架的这种功能.下面是具体的步骤:

      第一步,编写配置文件.配置文件的书写,采用了和Spring的配置文件applicationContext.xml一样的书写规则:

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- applicationContext.xml配置文件 -->
    <beans>
        <bean id="student1" class="com.xyy.domain.Student">
            <property name="name" value="hlhdidi"></property>
            <property name="age" value="13"></property>
            <property name="teacher" ref="teacher1"></property>
        </bean>
        <bean id="teacher1" class="com.xyy.domain.Teacher">
            <property name="name" value="cwb"></property>
            <property name="classes" value="高三九班"></property>
        </bean>
    </beans>

      第二步,编写JavaBean类,书写了两个JavaBean,其中Student类中有一个Teacher类的引用.

    //Student类
    public class Student implements Serializable{
        private String name;
        private int age;
        private Teacher teacher;
        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 Teacher getTeacher() {
            return teacher;
        }
        public void setTeacher(Teacher teacher) {
            this.teacher = teacher;
        }
        @Override
        public String toString() {
            return "Student [name=" + name + ", age=" + age + ", teacher=" + teacher + "]";
        }
        
        
    }
    //Teacher类
    public class Teacher implements Serializable{
        private String name;
        private String classes;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getClasses() {
            return classes;
        }
        public void setClasses(String classes) {
            this.classes = classes;
        }
        @Override
        public String toString() {
            return "Teacher [name=" + name + ", classes=" + classes + "]";
        }
        
    }

      第三步,也是最关键的一步,编写MyClassPathXmlApplicationContext类,在这个类里面做了如下操作:

      1.利用传入的参数获取xml文件的流,并且利用dom4j解析成Document对象

      2.对于Document对象获取根元素对象<beans>后对下面的<bean>标签进行遍历,判断是否有符合的id.

      3.如果找到对应的id,相当于找到了一个Element元素,开始创建对象,先获取class属性,根据属性值利用反射建立对象.

      4.遍历<bean>标签下的property标签,并对属性赋值.注意,需要单独处理int,float类型的属性.因为在xml配置中这些属性都是以字符串的形式来配置的,因此需要额外处理.

      5.如果属性property标签有ref属性,说明某个属性的值是一个对象,那么根据id(ref属性的值)去获取ref对应的对象,再给属性赋值.

      6.返回建立的对象,如果没有对应的id,或者<beans>下没有子标签都会返回null

      代码如下:

    public class MyClassPathXmlApplicationContext {
        private String xmlName;
        
        public MyClassPathXmlApplicationContext(String xmlName) {
            this.xmlName=xmlName;
        }
        
        public Object getBean(String id) {
            Object obj=null;            //声明引用.
            //进行xml的解析
            SAXReader reader=new SAXReader();
            try {
                Document document = reader.read(this.getClass().getClassLoader().getResourceAsStream(xmlName));
                Element root=document.getRootElement();
                //遍历.看是否有元素的id为传入的参数.
                List<Element> elements = root.elements();
                if(elements.size()>0) {
                    for(Element element:elements ) {
                        if(element.attributeValue("id").equals(id)) {//id相同开始创建对象
                            //采用反射创建对象.
                            String className=element.attributeValue("class");
                            Class beanClass=Class.forName(className);
                            obj=beanClass.newInstance();
                            //获取子标签的属性.
                            List<Element> attributes=element.elements();
                            if(attributes.size()>0) {
                                for(Element attribute:attributes) {
                                    String name=attribute.attributeValue("name");
                                    Field field = beanClass.getDeclaredField(name);
                                    field.setAccessible(true);
                                    if(attribute.attribute("ref")!=null) {
                                        //此属性的值是一个对象.这里由于直接调用getBean方法赋值给对象,返回的对象一定是Bean参数的对象,因此强制转换不会出问题
                                        String refid=attribute.attributeValue("ref");
                                        field.set(obj, getBean(refid));
                                    }
                                    else {
                                        //此属性值是一个字符串.这里单独处理int,float类型变量.如果不处理,会将String类型直接赋值给int类型,发生ClassCastException
                                        String value=attribute.attributeValue("value");
                                        //需要对类型进行判断
                                        if(value.matches("[0-9]+")) {
                                            //整数
                                            int x=Integer.parseInt(value);
                                            field.set(obj, x);
                                            continue;
                                        }
                                        if(value.matches("[0-9]*(\.+)[0-9]*")) {
                                            //浮点数
                                            float y=Float.parseFloat(value);
                                            field.set(obj, y);  //注意double可以接受float类型
                                            continue;
                                        }
                                        field.set(obj, value);//处理String类型
                                    }
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return obj;
        }
    }

      第四步:测试.

    @Test
        public void testMySpring() {
            MyClassPathXmlApplicationContext applicationContext=new MyClassPathXmlApplicationContext("applicationContext.xml");
            System.out.println(applicationContext.getBean("student1"));
        }

      测试结果:

    Student [name=hlhdidi, age=13, teacher=Teacher [name=cwb, classes=高三九班]]

      总结:

      dom4j是一个很好的解析xml的工具,而解析xml是一个很重要的基本功,对于理解框架原理有很大的帮助.反射结合xml文件的解析,可以实现在任何类中方便的创建任何对象.

  • 相关阅读:
    Ext.Ajax.request 传值问题
    类型反射与晚期绑定
    .net使用外部程序集拓展功能
    C#求解哈夫曼树
    几种获取操作系统语言的方法及其相似点与不同点
    C#调用非托管代码(C++方法)的2种方式
    构建可终结类型和可处置类型
    dockercompose 安装配置neo4j
    Windows 7 SDK Fails to Install with Return Code 5100 (GRMSDK_EN_DVD.iso)
    mysql密码修改方法
  • 原文地址:https://www.cnblogs.com/hlhdidi/p/6029839.html
Copyright © 2011-2022 走看看