Spring记录之模拟IoC(一)

6 篇文章 0 订阅

模拟Spring IoC容器

先回顾一下前文。前文说过,Spring的容器,通过读取配置文件,利用反射机制,实现了对象的创建,这是核心。

模拟步骤

  • 1.准备一个xml文件,配置好对象的关系
  • 2.根据配置文件初始化容器
  • 3.容器根据配置文件创建对象

目录结构
这里写图片描述

1.bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="chinese" class="spring.beans.Chinese"></bean>


    <bean id="english" class="spring.beans.English"></bean>
</beans>

2.准备容器

一个定义容器标准的接口

package spring.container;

/**
 * @author Administrator
 *
 */
public interface BeanFactory {

    public Object getBean(String id);
}

3. 两种解析xml方法

Spring容器初始化的同时,会解析xml配置文件,所以在容器的构造方法里解析xml文件.

package spring.container;

import java.util.HashMap;
import java.util.Map;
import spring.parser.ConfigParser;


/**
 * @author Administrator 
 *
 */
public class DomClassPathXMLApplicationContext implements BeanFactory {

    private Map<String, Object> beans = new HashMap<String, Object>();


    //parse xml file instantly this class is initializing
    public DomClassPathXMLApplicationContext(String path) {
        beans = ConfigParser.domParser(path);       
    }

    @Override
    public Object getBean(String id) {
        return beans.get(id);
    }
}
package spring.container;

import java.util.HashMap;
import java.util.Map;

import spring.parser.ConfigParser;

/**
 * @author Administrator
 *
 */
public class Dom4jClassPathXmlApplicationContext implements BeanFactory{


    private Map<String, Object> beans = new HashMap<String, Object>();

    //parse xml file instantly this class is initializing
    public Dom4jClassPathXmlApplicationContext(String path) {
        beans = ConfigParser.dom4jParser(path);
    }


    @Override
    public Object getBean(String id) {
        return beans.get(id);
    }

}

解析xml配置文件的核心方法(1.0)

public class ConfigParser {

    private static Map<String, Object> beans = new HashMap<String, Object>();

    /**
     * dom parse xml file
     * @param path
     * @return
     */
    public static Map<String, Object> domParser(String path) {
        org.w3c.dom.Document document = null;
        try {

            DocumentBuilderFactory factory = DocumentBuilderFactory
                    .newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            document = builder.parse(DomClassPathXMLApplicationContext.class
                    .getResourceAsStream(path));

        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(
                    "please check your configuration file. Make sure it is correct.");
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }

        // 获取所有<bean>节点
        NodeList beanList = document.getElementsByTagName("bean");

        for (int i = 0; i < beanList.getLength(); i++) {

            Node node = beanList.item(i);
            NamedNodeMap namedNodeMap = node.getAttributes();
            // dom解析属性是倒着来的,先class,再id,<bean id="" class=""></bean>
            String clazz = namedNodeMap.item(0).getNodeValue();
            String id = namedNodeMap.item(1).getNodeValue();
            Object object;
            try {

                object = Class.forName(clazz).newInstance();
                beans.put(id, object);

            } catch (InstantiationException | IllegalAccessException
                    | ClassNotFoundException e) {
                e.printStackTrace();
            }

        }
        return beans;
    }


    /**
     * dom4j parse xml file
     * @param path
     * @return
     */
    public static Map<String, Object> dom4jParser(String path) {

        // 1.parse xml configuration

        SAXReader reader = new SAXReader();
        org.dom4j.Document document = null;
        try {
            document = reader.read(Dom4jClassPathXmlApplicationContext.class
                    .getResourceAsStream(path));
        } catch (DocumentException e) {
            e.printStackTrace();
            throw new RuntimeException(
                    "please check your configuration file. Make sure it is correct.");
        }
        // 2. define xPath to fetch all <bean>
        String xpath = "//bean";
        List<Element> list = document.selectNodes(xpath);

        if (list.size() > 0) {
            for (Element beanEle : list) {

                String id = beanEle.attributeValue("id");
                String clazz = beanEle.attributeValue("class");


                try {
                    // use reflection to generate object
                    Object object = Class.forName(clazz).newInstance();
                    // put id and obj into a map
                    beans.put(id, object);



                } catch (InstantiationException | IllegalAccessException
                        | ClassNotFoundException e) {
                    e.printStackTrace();
                    throw new RuntimeException(
                            "please check your configuration file." + id
                                    + "not found!");
                } catch (SecurityException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        return beans;
    }
}

4. 测试用的bean类

定义了一个Human接口

public interface Human {
    public void speak();
}
.......
public class English implements Human{
    private String name = "British";

    @Override
    public void speak() {
        System.out.println(name + " speaks in English.");
    } 
}

......

public class Chinese implements Human{

    private String name = "中国人";

    @Override
    public void speak() {
        System.out.println(name + "说中文。");
    }

}

5. 测试

public class ContainerTest {

    @Test
    public void testContainer(){
        Dom4jClassPathXmlApplicationContext context = new Dom4jClassPathXmlApplicationContext("/bean.xml");
//      DomClassPathXMLApplicationContext context = new DomClassPathXMLApplicationContext("/bean.xml");
        Chinese chinese = (Chinese) context.getBean("chinese");
        English english = (English)context.getBean("english");
        chinese.speak();
        english.speak();

    }
}

结果如下
这里写图片描述

至此,一个简单的Spring IoC模拟1.0就实现完毕了,对象创建不是new出来的,而是通过配置文件解析,由容器创建的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值