Java面試知識點(八十二)仿照 Spring 實現簡單的 IOC

原文鏈接:https://segmentfault.com/a/1190000010745705

一、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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章