Java面试知识点(八十二)仿照 Spring 实现简单的 IOC

一、IOC实现

1.实现步骤

最简单的 IOC 容器只需 4 步即可实现,如下:

  • 加载 xml 配置文件,遍历其中的 <bean> 标签
  • 获取 <bean> 标签中的 id 和 class 属性,加载 class 属性对应的类,并创建 bean
  • 遍历 <bean> 标签中的 <property> 标签,获取属性值,并将属性值填充到 bean 中
  • 将 bean 注册到 bean 容器中

2.实现代码

【代码结构】

SimpleIOC     // IOC 的实现类,实现了上面所说的4个步骤
SimpleIOCTest    // IOC 的测试类
Car           // IOC 测试使用的 bean
Wheel         // 同上 
ioc.xml       // bean 配置文件

【容器实现类 SimpleIOC 的代码】

package learn.spring.ioc;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class SimpleIOC {
    // bean 容器
    private Map<String,Object> container = new HashMap<>(); 

    /**
     * 构造器
     * @param name 初始化的xml文件名
     * */
    public SimpleIOC(String name) throws Exception {
        loadBean(name);
    }

    /**
     * 从容器中获取bean
     * @param name 要获取的bean name
     * */
    public Object getBean(String name) {
        Object bean = container.get(name);
        if (bean == null) {
            throw new IllegalArgumentException("there is no the bean of " + name);
        }
        return bean;
    }

    /**
     * 把xml文件中的bean实例化并存放到容器中
     * @param name 初始化的xml文件名
     * */
    private void loadBean(String name) throws Exception {
        /*加载xml文件*/
        // 创建文件输入流
        File file = new File(name);
        // 创建xml解析器
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder document = factory.newDocumentBuilder();
        // 解析文件输入流,获得文档对象
        Document xml = document.parse(file);
        Element element = xml.getDocumentElement();
        // 获取所有子节点集合,即获得bean节点,这里根据xml文件来获得
        NodeList nodes = element.getChildNodes();
        // NodeList list = element.getElementsByTagName("bean"); //获取指定节点集合

        // 遍历bean节点
        for (int i = 0; i<nodes.getLength(); i++) {
            // 获得单个bean
            Node node = nodes.item(i);
            // 保证bean内部存在元素
            if (node instanceof  Element) {
                Element ele = (Element)node;
                String id = ele.getAttribute("id");
                String className = ele.getAttribute("class");

                // 加载beanClass
                Class beanClass = null;
                try {
                    beanClass = Class.forName(className);
                } catch (ClassNotFoundException  e) {
                    e.printStackTrace();
                    return ;
                }

                // 创建bean对象
                Object bean =  beanClass.newInstance();

                // 遍历property标签,跟遍历bean相同
                NodeList propertyList = ele.getElementsByTagName("property");
                for (int j = 0; j < propertyList.getLength(); j ++) {
                    Node propertyNode = propertyList.item(j);
                    if (propertyNode instanceof  Element) {
                        Element eleProperty = (Element) propertyNode;
                        // 获得属性
                        String propertyName = eleProperty.getAttribute("name");
                        String propertyValue = eleProperty.getAttribute("value");

                        // 利用反射将bean相关字段设置为可访问,原权限是private
                        Field field = bean.getClass().getDeclaredField(propertyName);
                        field.setAccessible(true);

                        // 存在value属性
                        if (propertyValue != null && propertyValue.length()>0) {
                            field.set(bean,propertyValue);
                        } else {// 属性不是基本类,而是其他类
                            String ref = eleProperty.getAttribute("ref");
                            if (ref == null || ref.length()==0) {
                                throw  new IllegalArgumentException("ref property error");
                            }
                            // 获取bean,并填充到相关字段
                            field.set(bean,getBean(ref));
                        }
                    }
                }
                registerBean(id,bean);
            }
        }
    }

    private void registerBean(String id, Object bean) {
        container.put(id,bean);
    }
}

【配置文件代码】

<beans>
    <bean id="wheel" class="learn.spring.ioc.Wheel">
        <property name="brand" value="Michelin" />
        <property name="specification" value="265/60 R18" />
    </bean>

    <bean id="car" class="learn.spring.ioc.Car">
        <property name="name" value="Mercedes Benz G 500"/>
        <property name="length" value="4717mm"/>
        <property name="width" value="1855mm"/>
        <property name="height" value="1949mm"/>
        <property name="wheel" ref="wheel"/>
    </bean>
</beans> 		

【容器测试使用的 bean 代码】

package learn.spring.ioc;

public class Wheel {
    private String brand;
    private String specification ;

    public String getBrand() {
        return brand;
    }

    public String getSpecification() {
        return specification;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public void setSpecification(String specification) {
        this.specification = specification;
    }

    @Override
    public String toString() {
        return this.getBrand()+":"+this.getSpecification();
    }
}

package learn.spring.ioc;

public class Car {
    private String name;
    private String length;
    private String width;
    private String height;
    private Wheel wheel;

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

    public void setLength(String length) {
        this.length = length;
    }

    public void setWidth(String width) {
        this.width = width;
    }

    public void setHeight(String height) {
        this.height = height;
    }

    public void setWheel(Wheel wheel) {
        this.wheel = wheel;
    }

    public String getName() {
        return name;
    }

    public String getLength() {
        return length;
    }

    public String getWidth() {
        return width;
    }

    public String getHeight() {
        return height;
    }

    public Wheel getWheel() {
        return wheel;
    }

    @Override
    public String toString() {
        return this.getName()+"+"+this.getHeight()
                +"+"+this.getLength()+"+"+this.getWidth()+"+"+this.getWheel().toString();
    }
}

【测试类】

package learn.spring.ioc;

public class Main {
    public static void main(String[] args) throws Exception {
        // 指定配置文件的路径
        String location =  "src/learn/spring/ioc/configuration";
        SimpleIOC simpleIOC = new SimpleIOC(location);
        Wheel wheel = (Wheel) simpleIOC.getBean("wheel");
        System.out.println(wheel);
        Car car = (Car) simpleIOC.getBean("car");
        System.out.println(car);
    }
}

【运行结果】

Michelin:265/60 R18
Mercedes Benz G 500+1949mm+4717mm+1855mm+Michelin:265/60 R18
发布了147 篇原创文章 · 获赞 835 · 访问量 27万+

猜你喜欢

转载自blog.csdn.net/qq_33945246/article/details/102719838
今日推荐