自定义简易SpringIOC-XML注入

Spring的各个模块构建的核心模块之上,Bean包装的是Object对象,Object里面一定是存在数据的,Context给数据提供一个生存空间的,Context就是发现和维护Bean之间的关系的,这个复杂的Bean的关系集合可以说是SpringIOC容器.)

步骤

手写简易版的SpringIOC步骤如下,本次实现过程基于如下的步骤的.

  1. 编写要解析的配置文件

  2. Xml解析获取Bean节点

  3. 通过反射获取对象并设置对象属性值

  4. 获取容器Bean对象

环境

环境搭建:IDEA,Java8,搭建Maven工程。

代码实现

POM文件

        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>

Bean对象

public class Person {
    private String name;
    private String age;
    private Book book;

    // 省略 get/set/ toString
}
public class Book {
    private String name;
    private String place;
    private String price;

    // 省略 get/set/ toString
}

Person.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- bean的配置文件 -->
    <bean id="book" class="bean.Book">
        <property name="name" value="think in java"></property>
        <property name="place" value="China"></property>
        <property name="price" value="79"></property>
    </bean>
    <bean id="person" class="bean.Person">
        <property name="name" value="grl"></property>
        <property name="age" value="11"></property>
        <property name="book" ref="book"></property>
    </bean>
</beans>

IOC

ApplicationContext 接口

public interface ApplicationContext {
    Object getBean(String name);
}

ClassPathXmlApplicationContext 实现

import ioc.factory.ApplicationContext;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;

/**
 * @Desc: TODO 基于类路径加载配置文件
 */
public class ClassPathXmlApplicationContext implements ApplicationContext {

    /**
     * 要解析的配置文件
     */
    private File file;
    /**
     * 存放Bean对象的实例
     */
    private Map map = Collections.synchronizedMap(new HashMap());

    /**
     * 解析配置文件,实例化容器,将对象存放入容器当中
     */
    public ClassPathXmlApplicationContext(String configFile) throws Exception {
        URL url = this.getClass().getClassLoader().getResource(configFile);
        try {
            file = new File(url.toURI());
            xmlParse(file);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解析xml文件
     *
     * @param file
     */
    private void xmlParse(File file) throws DocumentException,
                                            ClassNotFoundException,
                                            IllegalAccessException,
                                            InstantiationException,
                                            NoSuchFieldException {
        // 创建saxReader对象
        SAXReader reader = new SAXReader();
        // 通过read方法读取一个文件 转换成Document对象
        Document document = reader.read(file);
        // 获取根节点【beans】
        Element rootElement = document.getRootElement();
        // 获得根节点下的所有子节点【bean】
        List<Element> elements = rootElement.elements();

        Iterator iterator = elements.iterator();
        while (iterator.hasNext()) {
            Element element = (Element) iterator.next();

            String id = element.attributeValue("id");
            String classPath = element.attributeValue("class");

            // 使用java的反射机制初始化类
            Class<?> clazz = Class.forName(classPath);
            // 反射调用有参函数
            Object newInstance = clazz.newInstance();
            // 获取类的所有方法,然后通过set方法给这个对象设置属性值
            Method[] methods = clazz.getDeclaredMethods();
            // 获取属性【properties】
            List<Element> sonEle = element.elements();
            // 遍历属性下的name,value
            for (Element el : sonEle) {
                // 获取配置文件属性名称
                String attField = el.attributeValue("name");
                Object value = el.attributeValue("value");
                if (value == null) {
                    // 属性为引用对象的属性
                    String ref = el.attributeValue("ref");
                    value = map.get(ref);
                }

                // 获得私有属性
                Field declaredField = clazz.getDeclaredField(attField);
                // 暴力反射获取私有属性
                declaredField.setAccessible(true);
                // 给有参构造函数赋值【value】
                declaredField.set(newInstance, value);
            }

            // 将对象添加到容器里面
            map.put(id, newInstance);
        }
    }

    /**
     * 获取Bean对象
     */
    public Object getBean(String name) {
        return map.get(name);
    }
}

测试

public class Test {
    public static void main(String[] args) throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("Person.xml");
        Person person = (Person) context.getBean("person");
        System.out.println(person);
    }
}

控制台输出:Person{name='grl', age='11', book=Book{name='think in java', place='China', price='79'}}

总结一句话:Java通过配置文件的解读,反射拿到类实例,获取该类的所有Set方法,过滤取出和Xml中配置的属性值,然后反射动态给该属性设置(Xml中配置的值),这样调用相应属性的get方法就可以获取到相应的值啦.

 

原文地址:https://www.cnblogs.com/mmdz/p/15449180.html