手寫SpringIOC之 xml配置

今日,閒來無事,根據自己的理解手寫一版SpringIOC的注入流程,儘管是簡化版本的,但是依舊能夠幫助我們很好的理解SpringIOC爲什麼能夠做到自動注入,他的底層實現,又究竟做了哪些操作呢?下面讓我們一起進行探索吧!

一.項目中可能會使用到的jar資源 本想木採用maven 的形式,因爲要解析xml所以我這裏的技術選型是 dom4j 有其他想法的小夥伴可以自己選擇!

1.pom文件

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

2.自定義異常

public class LubanSpringException extends RuntimeException {

    public LubanSpringException(String msg){
        super(msg);
    }
}

3.SpringIOC的手動注入流程

import com.luban.exception.LubanSpringException;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author 皇甫
 */
public class SpringBeanFactory {
    /**
     * 定義一個HashMap映射,映射beanName和對應類的關係
     */
    private Map<String,Object> map = new HashMap<String, Object>();
    public void springBeanFactory(String xml){
        xmlAnalysis(xml);
    }

    /**
     * 解析XML
     * @param xml
     */
    private void xmlAnalysis(String xml){
        //讀取配置文件
        File file = new File(this.getClass().getResource("/").getPath()+"/"+xml);
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(file);
            Element rootElement = document.getRootElement();
            //判斷是否有自動注入的配置
            Attribute attribute = rootElement.attribute("default-autowire");
            boolean flag = false;
            if(attribute != null){
                flag = true;
            }
            for (Iterator<Element> it = rootElement.elementIterator(); it.hasNext();) {
                Element element = it.next();
                // do something
                Attribute attributeId = element.attribute("id");
                String beanId = attributeId.getValue();
                Attribute attributeClassName = element.attribute("class");
                String beanClassName = attributeClassName.getValue();
                Class clazz = Class.forName(beanClassName);
                /**
                 * 維護依賴關係
                 * 遍歷子集標籤 手動設置注入
                 */
                Object object = null;
                //遍歷子集 bean
                for (Iterator<Element> childIt = element.elementIterator(); childIt.hasNext();) {
                    Element childElement = childIt.next();
                    // do something
                    //如果爲set注入
                    if(childElement.getName().equals("property")){
                        //獲取當前對象的類對象
                        object = clazz.newInstance();
                        //獲取當前類所依賴的類的BeanName
                        String childElementRefValue = childElement.attribute("ref").getValue();
                        //根據需要的BeanName去Map映射中尋找對應的對象
                        Object o = map.get(childElementRefValue);
                        String nameValue = childElement.attribute("name").getValue();
                        //根據注入的名字獲取屬性名
                        Field field = clazz.getDeclaredField(nameValue);
                        field.setAccessible(true);
                        //設置屬性的值
                        field.set(object, o);
                    //如果爲構造方法注入
                    }else if(childElement.getName().equals("constructor-arg")){
                        //獲取要注入的對象的id
                        String refValue = childElement.attribute("ref").getValue();
                        //取出Map
                        Object o = map.get(refValue);
                        //向構造方法中注入文件
                        Constructor constructor = clazz.getConstructor(o.getClass().getInterfaces()[0]);
                        object = constructor.newInstance(o);
                    }else{

                    }
                }

                //如果設置了自動注入
                if(flag){
                    //如果爲根據類型注入
                    if(attribute.getValue().equals("byType")){
                        //判斷此類是否有依賴 和獲取全部的屬性
                        Field[] fields = clazz.getDeclaredFields();
                        for (Field field : fields) {
                            //獲取對象的類型
                            Class fieldType = field.getType();
                            int count = 0;
                            Object injectObject = null;
                            for (String s : map.keySet()) {
                                if(map.get(s).getClass().getInterfaces()[0].getName().equals(fieldType.getName())){
                                    count++;
                                    injectObject = map.get(s);
                                }
                            }
                            //如果對象類型匹配個數大於1證明由兩個類型,需要拋出異常
                            if(count>1){
                                throw new LubanSpringException("只需要一個類型,卻找到了兩個類型");
                            }else{
                                object = clazz.newInstance();
                                Field[] fs = clazz.getDeclaredFields();
                                field.setAccessible(true);
                                field.set(object, injectObject);
                            }
                        }
                    //如果設置爲根據名字注入
                    }else if(attribute.getValue().equals("byName")){
                        //判斷此類是否有依賴
                        Field[] fields = clazz.getDeclaredFields();
                        for (Field field : fields) {
                            Class fieldType = field.getType();
                            for (String s : map.keySet()) {
                                if (map.get(s).getClass().getInterfaces()[0].getSimpleName().equals(fieldType.getSimpleName())) {
                                    object = clazz.newInstance();
                                    field.setAccessible(true);
                                    field.set(object, map.get(s));
                                }
                            }
                        }
                    }

                }

                //如果沒有依賴,創建對象
                if(object==null){
                    object = clazz.newInstance();
                }
                map.put(beanId, object);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Object getBean(String beanName){
        return map.get(beanName);
    }
}

二.測試

1.定義DAO

/**
 * @author 皇甫
 */
public interface UserDao {
    /**
     * 查詢數據路
     */
    public void find();
}

2.定義DAO實現類

import com.luban.dao.UserDao;

public class UserDaoImpl implements UserDao {
    public void find() {
        System.out.println("查詢數據庫");
    }
}

3.定義Service接口

/**
 * @author 皇甫
 */
public interface UserService {
    /**
     * 查詢
     */
    public void find();
}

4.定義Service實現類

import com.luban.dao.UserDao;
import com.luban.service.UserService;

/**
 * @author 皇甫
 */
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public void find() {
        userDao.find();
    }
}

5.定義xml

<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire = "byName">
    <bean id="dao" class="com.luban.dao.impl.UserDaoImpl"></bean>
    <bean id="dao1" class="com.luban.dao.impl.UserDaoImpl"></bean>
    <bean id="service" class="com.luban.service.impl.UserServiceImpl"></bean>
</beans>

6.測試

import com.luban.service.UserService;
import com.luban.util.SpringBeanFactory;
import org.junit.Test;

/**
 * @author 皇甫
 */
public class TestSpringIoc {
    @Test
    public void test1(){
        SpringBeanFactory springBeanFactory = new SpringBeanFactory();

        springBeanFactory.springBeanFactory("spring.xml");
        UserService service = (UserService) springBeanFactory.getBean("service");
        service.find();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章