spring-5-spring源碼(模擬自動注入)

 

1、定義接口

package com.service;
public interface Service {
    public void queryDao();
}


package com.dao;
public interface Dao {
    public void query();
}

  

2、實現類

package com.service;
import com.dao.Dao;
public class ServiceImpl implements Service {
     Dao dao ;
     
     Dao getDao() {
        return dao;
    }

    public void setDao(Dao dao) {
        this.dao = dao;
    }

    public void queryDao() {
        System.out.println("開始調用Dao!");
        dao.query();
    }
}






package com.dao;

public class DaoImpl implements Dao {
    @Override
    public void query(){
        System.out.println("操作數據庫!");
    }
}

  

3、工廠類

package com.util;

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.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class BeanFactory {
    public Map map = new HashMap<String,Object>();

    public BeanFactory(String xml) {
        parseXml(xml);
    }

    public void parseXml(String xml){
        try {
            File file = new File(this.getClass().getResource("/").getPath()+"//"+xml);
            SAXReader reader = new SAXReader();
            Document document = reader.read(file);
            Element root = document.getRootElement();

            for (Iterator<Element> it1 = root.elementIterator(); it1.hasNext();) {
                Element element = it1.next();
                Attribute elementAttrId = element.attribute("id");
                String elementId = elementAttrId.getValue();
                Attribute elementAttrClass = element.attribute("class");
                String elementClass = elementAttrClass.getValue();

                //實例化對象
                Class clazz = Class.forName(elementClass);
                Object beanObject = clazz.newInstance();
                map.put(elementId,beanObject);

                for (Iterator<Element> it2 = element.elementIterator(); it2.hasNext();) {
                    Element element2 = it2.next();
                    if("property".equals(element2.getName())){
                        String attributeName = element2.attribute("name").getValue();
                        String attributeRef =  element2.attribute("ref").getValue();

                        //獲取目標對象中的所有屬性,[規則:屬性的名字一定和property中的那麼保持一致]
                        Field field = beanObject.getClass().getDeclaredField(attributeName);

                        //說明依賴已經存在map中,需要將依賴注入到目標中的屬性中
                        Object injectInObject = map.get(attributeRef);
                        if(map.get(attributeRef)==null){
                            System.out.println("依賴還沒有注入,請檢查以來是否在"+clazz.getName()+"對象之前已經注入!");
                        }
               //使用反射set方法必須傳的值,否則會報IllegalAccessException:"BeanFactory不能訪問com.service類的成員。ServiceImpl與修飾符" field.setAccessible(true); field.set(beanObject,injectInObject); } } } } catch (Exception e) { e.printStackTrace(); } } public Object getBean(String beanName){ if(map == null || map.get(beanName)==null){ return null; } return map.get(beanName); } }

  

4、測試類

public static void main(String args[]){
        BeanFactory beanFactory = new BeanFactory("spring.xml");
        System.out.println(beanFactory.map);
        Service service = (ServiceImpl)beanFactory.getBean("service");
        service.queryDao();
    }

  

使用構造方式依賴注入

package com.util;

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;

public class BeanFactory {
    public Map map = new HashMap<String,Object>();

    public BeanFactory(String xml) {
        parseXml(xml);
    }

    public void parseXml(String xml){
        try {
            File file = new File(this.getClass().getResource("/").getPath()+"//"+xml);
            SAXReader reader = new SAXReader();
            Document document = reader.read(file);
            Element root = document.getRootElement();

            for (Iterator<Element> it1 = root.elementIterator(); it1.hasNext();) {
                Element element = it1.next();
                Attribute elementAttrId = element.attribute("id");
                String elementId = elementAttrId.getValue();
                Attribute elementAttrClass = element.attribute("class");
                String elementClass = elementAttrClass.getValue();
                //實例化對象
                Class clazz = Class.forName(elementClass);
                Object beanObject = clazz.newInstance();

                for (Iterator<Element> it2 = element.elementIterator(); it2.hasNext();) {
                    Element element2 = it2.next();
                    //實例化對象,如果子標籤是property則默認使用setter方法,並且默認構造
                    String attributeName = element2.attribute("name").getValue();
                    String attributeRef =  element2.attribute("ref").getValue();
                    Object injectInObject = null;
                    if("property".equals(element2.getName())){
                        injectInObject = map.get(attributeRef);
                        //說明依賴不存在map中,需要將依賴注入到目標中的屬性中
                        if(injectInObject==null){
                            System.out.println("依賴對象還沒有註冊到容器!");
                        }

                        //獲取目標對象中的所有屬性,[規則:屬性的名字一定和property中的那麼保持一致]
                        Field field = beanObject.getClass().getDeclaredField(attributeName);

                        field.setAccessible(true);
                        field.set(beanObject,injectInObject);

                    //當然構造方法中可以有多個參數,這裏只默認爲一個注入對象
                    }else if("constructor-arg".equals(element2.getName())){
                        injectInObject = map.get(attributeRef);
                        if(injectInObject==null){
                            System.out.println("依賴對象還沒有註冊到容器!");
                        }
                        Constructor constructor= clazz.getConstructor(injectInObject.getClass().getInterfaces()[0]);
                        beanObject = constructor.newInstance(injectInObject);
                    }else{
                        System.out.println("解析中出現特殊子標籤,請繼續編寫!");
                    }
                }

                if(beanObject==null){
                    beanObject = clazz.newInstance();
                }
                map.put(elementId,beanObject);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Object getBean(String beanName){
        if(map == null || map.get(beanName)==null){
          return null;
        }
        return map.get(beanName);
    }
}

  

模擬自動裝配方式,並且屬性方式>自動裝配,自定義異常

1、自動裝配

  byType方式:如果xml中beans標籤中包含自動裝配屬性並且value=byType,我們要循環目標對象的屬性,並且使用屬性查找map(已注入的對象)是否一致(這裏判斷的是接口名字),如果一致使用set方式注入,如果map中出現兩個則需要拋出自定義異常(再容器中找到兩個一樣的注入對象)

 

 

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