Spring讀取xml配置文件的原理與實現


本篇博文的目錄:

一:前言

二:spring的配置文件

三:依賴的第三方庫、使用技術、代碼布局

四:Document實現

五:獲取Element的實現

六:解析Element元素

七:Bean創造器

八:Ioc容器的創建

九:總結

一:前言:

Spring作為Bean的管理容器,在我們的項目構建中發揮了舉足輕重的作用,尤其是控制反轉(IOC)和依賴(DI)注入的特性,將對象的創建完全交給它來實現,當我們把與其他框架進行整合時,比如與Mybatis整合,可以把sqlMapClientTemplate、數據源等Bean交給它來管理,這樣在我們程序需要的時候,只需要調用它的getBean(String id)方法就可以獲取它的一個實例。這一點我們都知道它是利用反射的原理,取得class然后獲取constructor-arg配置的參數,然后調用newInstance()方法進行實例化的,那么我們在spring配置文件中配置的Bean的屬性,比如Lazy-int、AutoWire屬性Spring是如何解析的呢?這背后又是怎樣的原理呢。這就是本篇博文將要探討的問題,我們將深入到代碼層面,看一看Spring解析Xml的具體原理

二:Spring的配置文件

我們先來看一個簡單的Spring配置文件,由配置文件我們看到了Spring配置文件的一系列屬性,配置Bean的id,class屬性,還有Lazy-int、AutoWire、SingleTon等屬性,配置了這些東西,那么Spring就會按照我們配置的東西進行解析,從而得到我們需要的值。

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context.xsd  
    http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd  
    http://www.springframework.org/schema/tx  
    http://www.springframework.org/schema/tx/spring-tx.xsd  
    http://www.springframework.org/schema/jdbc  
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd  
    http://www.springframework.org/schema/cache  
    http://www.springframework.org/schema/cache/spring-cache-3.1.xsd  
    http://www.springframework.org/schema/aop  
    http://www.springframework.org/schema/aop/spring-aop.xsd  
    http://www.springframework.org/schema/util  
    http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="pad1" class="com.wyq.Bean.Pad" scope="singleton">
        <constructor-arg>
            <value type="java.lang.double">1999.9</value>
        </constructor-arg>
    </bean>
    <!-- 懶加載 -->
    <bean id="pad2" class="com.wyq.Bean.Pad" lazy-init="true"
        autowire="no"></bean>

    <bean id="person" class="com.wyq.Bean.Person" autowire="byName">
        <property name="name" value="Yrion"></property>
    </bean>

</beans>

三:依賴的第三方庫、使用技術、代碼布局

spring解析xml配置的第三方庫需要的是dom4j,使用的技術是java,代碼布局會按照Document、Element、BeanCreator的方式進行,首先定義相關的接口,然后定義子類去實例化,我們來展示一下Spring解析配置文件接口的思維導圖,從中可以看出我們定義了一系列的讀取屬性的接口,比如AutoWire屬性,因為有兩種情況ByName和no、byType三種情況(這里只為了說明問題,我們只定義兩個實現類,正式的話是三個實現類),這里采用的是狀態設計模式,設計一個總接口,然后對不同的情況,我們定義相關的實現類,是那種情況,就返回具體的類。如圖展示的是接口和具體的實現類,接下來我們將會按照這樣的方式去講解每一個接口對應的實現類。

四:獲取Document實現

按照從大到小的思維,我們先來實現DocumenHoler接口,可以看出這個接口我們只定義了一個方法,根據路徑返回具體的Document。然后我們來寫具體的實現子類,有了這樣的類,我們只需要傳入一個路徑,那么就會返回一個模擬的Document對象

import org.dom4j.Document;

public interface DocumentHolder {
    
    Document getDocument(String filePath);

}
import java.io.File;
import java.util.HashMap;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.io.SAXReader;

public class XMLDocumentHolder implements DocumentHolder{
    
    //建立一個HashMap用來存放字符串和文檔
    private Map<String, Document> docs = new HashMap<String, Document>();

    @Override
    public Document getDocument(String filePath) {
        
        Document doc=this.docs.get(filePath);//用HashMap先根據路徑獲取文檔
        
        if (doc==null) {
            
            this.docs.put(filePath, readDocument(filePath)); //如果為空,把路徑和文檔放進去
            
        }
        
        return  this.docs.get(filePath);
    }

    /**
     * 根據路徑讀Document
     * @param filePath
     * @return
     */
    private Document readDocument(String filePath) {
        
        Document doc =null;
        
        try {
            
            SAXReader reader = new SAXReader(true);//借用dom4j的解析器
            
            reader.setEntityResolver(new IocEntityResolver());
            
            File xmlFile = new File(filePath); //根據路徑創建文件
            
             doc = reader.read(xmlFile);//用dom4j自帶的reader讀取去讀返回一個Document
            
        } catch (Exception e) {
            
            e.printStackTrace();
            
        }
        return doc;
    }
    

}

五:獲取Element的接口實現

有了Document,按照從大到小的邏輯,我們就需要解析Element元素了,也就是具體的元素加載器,首先我們先來定義一個接口,然后再定義具體的類去實現這個接口。中間主要定義了三個方法添加元素和獲取元素,和獲取所有的元素,在子類中定義了一個HashMap用於鍵用來存儲屬性名,值用來存儲具體的Element元素。

import java.util.Collection;
import org.dom4j.Document;
import org.dom4j.Element;

/**
 * 加載Element元素
 * @author Yiron
 *
 */
public interface ElementLoader {
    
    void addElements(Document doc);//添加元素
    
    Element getElement(String id);//獲取元素
    
    Collection<Element> getElements();//獲取所有的元素

}
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;

public class ElementLoaderImpl implements ElementLoader{

    private Map<String, Element> elements=new HashMap<String, Element>();

    public void addElements(Document doc) {

        @SuppressWarnings("unchecked")
        List<Element> eles = doc.getRootElement().elements();

        for (Element e : eles) {

            String id=e.attributeValue("id");

            elements.put(id, e);
        }
    }

    public Element getElement(String id) {

        return elements.get(id);
    }

    public Collection<Element> getElements() {

        return this.elements.values();
    }

}

六:解析Element元素

在第五步中,我們主要是獲取了Element元素,獲取到了之后,我們就要對其進行解析了。我們首先來定義一個解析Element的接口,接口里面的方法主要是對xml文件配置的元素作出解析,比如boolean isLazy(Element element)就是對其是否進行懶加載進行判斷,然后實現該接口:

import java.util.List;
import org.dom4j.Element;

/**
 * 解析Element元素
 * @author Yiron
 *
 */
public interface ElementReader {
    
    boolean isLazy(Element element);
    
    List<Element> getConstructorElements(Element element);
    
    String getAttribute(Element element,String name);
    
    boolean isSingleTon(Element element);
    
    List<Element> getPropertyElements(Element element);
    
    AutoWire getAutoWire(Element element);
    
    List<DataElement> getConstructorValue(Element element);
    
    List<PropertyElement> getPropertyValue(Element element);
    
}
package com.wyq.ResolveElement;

import java.util.ArrayList;
import java.util.List;

import org.dom4j.Element;
import org.omg.PortableServer.ID_ASSIGNMENT_POLICY_ID;

public class ElementReaderImpl implements ElementReader{

    /**
     * 判斷是否延遲加載
     */
    @Override
    public boolean isLazy(Element element) {

        String lazy = getAttribute(element, "lazy-int");//得到是否懶加載這個元素

        Element parent = element.getParent();

        Boolean parentLazy = new Boolean(getAttribute(parent, "default-lazy-int"));

        if (parentLazy) {

            if ("false".equals(lazy)) return false;

            return true;

            
        }else {

            if ("true".equals(lazy))  return true;

            return false;
        }
    }

    /**
     * 獲取constructor-arg節點
     */
    @Override
    public List<Element> getConstructorElements(Element element) {

        List<Element> childrens = element.elements();//得到bean節點下的所有節點

        List<Element> reslut=new ArrayList<Element>();//存放節點的鏈表

        for (Element e : childrens) {//遍歷

            if ("constructor-arg".equals(e.getName())) {//如果是constructor-arg節點
            
                reslut.add(e);//放入到預設的鏈表中
            }

        }
        return reslut; //返回這個鏈表
    }

    /**
     * 根據元素的name獲取元素的值
     */
    public String getAttribute(Element element, String name) {

         String value = element.attributeValue(name);
    
         return value;
    }

    /**
     * 判斷是不是單例模式
     */
    public boolean isSingleTon(Element element) {

        Boolean singleTon = new Boolean(getAttribute(element, "singleTon"));

        return singleTon;
    }

    
    /**
     * 獲得自動注入
     */
    @Override
    public AutoWire getAutoWire(Element element) {

        String value = this.getAttribute(element, "autoWire");

        String parentValue=this.getAttribute(element.getParent(),"default-autowire");

        if ("no".equals(parentValue)) {

            if ("byName".equals(parentValue)) {

                return new ByNameAutoWire(value);
                
            }else {
                return new NoAutoWire(value);
            }
        }else if ("byName".equals(parentValue)) {
            
            if("no".equals(value)) return new NoAutoWire(value);
            
            return new ByNameAutoWire(value);

        }

        return new NoAutoWire(value);
    }

    @Override
    public List<DataElement> getConstructorValue(Element element) {
        
        List<Element> cons=getConstructorElements(element);
        
        List<DataElement> result = new ArrayList<DataElement>();
        
        for (Element e : cons) {
            
            List<Element> els = e.elements();
            
            DataElement dataElement = getDataElement(els.get(0));
            
            result.add(dataElement);
            
        }
        
        return result;
    }

    @Override
    public List<PropertyElement> getPropertyValue(Element element) {
        
        List<Element> properties=getPropertyElements(element);
        
        List<PropertyElement> reslut=new ArrayList<PropertyElement>();
        
        for (Element e : properties) {
            
            List<Element> els=e.elements();
            
            DataElement dataElement = getDataElement(els.get(0));
            
            String value = getAttribute(e, "name");
            
            PropertyElement pe = new PropertyElement(value, dataElement);
            
            reslut.add(pe);
            
        }
        
        
        return reslut;
    }
    
    
    private DataElement getDataElement(Element element){
        
        String name=element.getName();
        
        if ("value".equals(name)) {
            
            String classTypeName=element.attributeValue("type");
            
            String data = element.getText();
            
            return new ValueElement(getValue(classTypeName,data));
            
        }else if ("ref".equals(name)) {
            
            return new RefElement(this.getAttribute(element, "bean"));
            
        }
        
        return null;
    }
    
    private Object getValue(String className,String data){
        
        if (isType(className,"Integer")) {
            
            return Integer.parseInt(data);
            
        }else {
            
            return data;
        }
        
    }

    private boolean isType(String className, String type) {
        
        if (className.indexOf(type)!=-1) {
            
            return true;
            
        }else {
            
            return false;
            
        }
        
    }

    @Override
    public List<Element> getPropertyElements(Element element) {
    
           List<Element> elements = element.elements();
        
          return elements;
    }
    

}

6.2:解析Element的時候,我們定義了幾個接口,我們來看看自動注入的源代碼,自動注入返回三種情況,我們來模擬實現其中兩種ByNameAutoWire與NoAutoWire。還有DataElement,其子類分別是:RefElement和ValueElement分別表示引用元素和值元素。

public interface AutoWire {  //自動注入
    
    String getValue();

}
public class ByNameAutoWire implements AutoWire{
    
    private String value;

    public ByNameAutoWire(String value) {
        
        this.value = value;
    }

    @Override
    public String getValue() {
        
        return value;
    }

}
public class NoAutoWire implements AutoWire{
    
    String value;

    public NoAutoWire(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
    
}
public interface DataElement {
    
    String getType();
    
    Object getValue();

}
public class RefElement implements DataElement{
    
    private Object value;
    
    public  RefElement(Object value) {
        
        this.value=value;
    }
    
    @Override
    public String getType() {
        
        return "ref";
    }

    @Override
    public Object getValue() {
        
        return this.value;
    }
}
public class ValueElement implements DataElement {
    
    private Object value;

    public ValueElement(Object value) {
        
        this.value = value;
    }

    @Override
    public String getType() {
        
        return "value";
    }

    @Override
    public Object getValue() {
        
        return this.value;
    }

}

七:Bean創造器

主要創造Bean不使用默認構造器和使用定義的construction-arg參數,當我們配置構造參數的時候,就會拿到這些信息,然后進行反射來調用構建對象,其中還包括獲取Setter方法。其代碼如下:

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

public interface BeanCreator  { 

    Object createBeanUseDefaultConstruct(String className);//使用空構造器

    Object createBeanUseDefineConstruce(String className,List<Object> args);//使用定義的構造器

    Map<String, Method> getSetterMethodsMap(Object obj);

    void executeMethod(Object object,Object argBean,Method method);

}
package com.wyq.Bean;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BeanCreatorImpl implements BeanCreator{

    @Override
    public Object createBeanUseDefaultConstruct(String className) {

         Object object=null;
        try {
            Class clazz = Class.forName(className);

            object= clazz.newInstance();
            
        } catch (ClassNotFoundException e) {

            e.printStackTrace();
        } catch (InstantiationException e) {

            e.printStackTrace();

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return object;

    }
    /**
     * className:類的名字
     * args:配置的構造參數
     */

    @Override
    public Object createBeanUseDefineConstruct(String className, List<Object> args) {

        Class[] argsClass=getArgsClasses(args);

        try {

            Class clazz = Class.forName(className);

            Constructor constructor=findConstructor(clazz,argsClass);



        } catch (Exception e) {
            // TODO: handle exception
        }

        return null;
    }

    /**
     * 根據類型和參數查找構造器
     * @param clazz
     * @param argsClass
     * @return
     */
    private Constructor findConstructor(Class clazz, Class[] argsClass) throws NoSuchMethodException{

        Constructor constructor=  getConstructor(clazz,argsClass);

        if (constructor==null) {

            Constructor[] constructors = clazz.getConstructors();

            for (Constructor c : constructors) {

                Class[] constructorArgsClass = c.getParameterTypes();

                if (constructorArgsClass.length==argsClass.length) {

                    if (isSameArgs(argsClass,constructorArgsClass)) {

                        return c;

                    }

                }
            }

        }

        return null;
    }

    private boolean isSameArgs(Class[] argsClass, Class[] constructorArgsClass) {

        for (int i = 0; i < argsClass.length; i++) {

            try{

                argsClass[i].asSubclass(constructorArgsClass[i]);

                if (i==(argsClass.length-1)) {

                    return true;

                }}catch (Exception e) {
                    e.printStackTrace();

                    break;

                }
        }

        return false;
    }
    private Constructor getConstructor(Class clazz, Class[] argsClass) throws SecurityException, NoSuchMethodException {

        try {

            Constructor constructor = clazz.getConstructor(argsClass);

            return constructor;

        } catch (Exception e) {

            return null;
        }
    }


    private Class[] getArgsClasses(List<Object> args) {

        //裝有class類的list集合
        List<Class> reslut =new ArrayList<Class>();

        for (Object arg : args) {

            reslut.add(getClass(arg));
        }

        Class[] a = new Class[reslut.size()];
        
        return reslut.toArray(a);
    }

    private Class getClass(Object obj) {

        if (obj instanceof Integer) {

            return Integer.TYPE;

        }else if (obj instanceof Double) {

            return Double.TYPE;
        }else if (obj instanceof Long) {

            return Long.TYPE;

        }else if (obj instanceof Float) {

            return Float.TYPE;

        }else if (obj instanceof Character) {

            return Character.TYPE;

        }else if (obj instanceof Byte) {

            return Byte.TYPE;
        }

        return obj.getClass();
    }

    @Override
    public void executeMethod(Object object, Object argBean, Method method) {

        try {
            Class[] paramterTypes = method.getParameterTypes();

            if (paramterTypes.length==1) {

                if (isMethodArgs(method,paramterTypes[0])) {

                    method.invoke(object, argBean);

                }

            }

        } catch (Exception e) {

            try {
                throw new BeanCreateException("autoWire exception"+e.getMessage());

            } catch (BeanCreateException e1) {

                e1.printStackTrace();
            }
        }

    }

    private boolean isMethodArgs(Method method, Class class1) {

        Class[] c = method.getParameterTypes();

        if (c.length==1) {

            try {
                
                class1.asSubclass(c[0]);

                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }

        }

        return false;
    }
    @Override
    public Map<String, Method> getSetterMethodsMap(Object obj) {
        
      List<Method>    methods=getSetterMethodsList(obj);
      
       Map<String, Method> result=new HashMap<String ,Method>();
        
        for (Method method : methods) {
            
            String propertyName=getMethodNameWithOutSet(method.getName());
            
        }
        
        
        
        

        return null;
    }
    
    /**
     * 還原setter方法
     * @param methodname
     * @return
     */
    
    private String getMethodNameWithOutSet(String methodname) {
        
        String propertyName=methodname.replace("set", "");
        
        String firstWord=propertyName.substring(0,1);
        
        String lowerFirstWord = firstWord.toLowerCase();
        
        return propertyName.replaceFirst(firstWord, lowerFirstWord);
        
    }
    
    
    private List<Method> getSetterMethodsList(Object obj) {
        
        Class clazz = obj.getClass();
        
        List<Method> result=new ArrayList<Method>();
        
        Method[] methods = clazz.getMethods();
        
        for (Method method : methods) {
            
            if (method.getName().startsWith("Set")) {
                
                result.add(method);
                
            }
        }
        
        return result;
    }
}

八:定義自己的IoC容器:

首先我們來定義自己的ApplicationContext接口,其中有getBean(String id)方法,通過這個方法就可以獲取具體的對象實例,也是我們使用Spring框架中用的最多的一個方法。然后來定義具體的實現子類

 

public interface ApplicationContext {
    
    Object getBean(String id);
    
    boolean containsBean(String id);
    
    boolean isSingleton(String id);
package com.wyq.Ioc;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;

import com.wyq.Bean.BeanCreateException;
import com.wyq.Bean.BeanCreator;
import com.wyq.Bean.BeanCreatorImpl;
import com.wyq.Element.ElementLoader;
import com.wyq.Element.ElementLoaderImpl;
import com.wyq.ReadXml.DocumentHolder;
import com.wyq.ReadXml.XMLDocumentHolder;
import com.wyq.ResolveElement.AutoWire;
import com.wyq.ResolveElement.ByNameAutoWire;
import com.wyq.ResolveElement.DataElement;
import com.wyq.ResolveElement.ElementReader;
import com.wyq.ResolveElement.ElementReaderImpl;
import com.wyq.ResolveElement.NoAutoWire;
import com.wyq.ResolveElement.PropertyElement;
import com.wyq.ResolveElement.RefElement;
import com.wyq.ResolveElement.ValueElement;
import com.wyq.SetInput.PropertyHandler;
import com.wyq.SetInput.PropertyHandlerImpl;

public class AbstractApplicationContext implements ApplicationContext {

    protected ElementLoader elementLoader = new ElementLoaderImpl();

    protected DocumentHolder documentHolder = new XMLDocumentHolder();

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

    protected BeanCreator beanCreator = new BeanCreatorImpl();

    protected ElementReader elementReader = new ElementReaderImpl();

    protected PropertyHandler propertyHandler = new PropertyHandlerImpl();

    protected void setUpElements(String[] xmlPaths){

        URL classPathUrl = AbstractApplicationContext.class.getClassLoader().getResource(".");

        String classpath;
        
        try {
            classpath = java.net.URLDecoder.decode(classPathUrl.getPath(), "utf-8");

            for (String path : xmlPaths) {

                Document doc = documentHolder.getDocument(classpath + path);

                elementLoader.addElements(doc);

            }
        } catch (UnsupportedEncodingException e) {

            e.printStackTrace();
        }
    }

    @Override
    public Object getBean(String id) {

        Object bean = this.beans.get(id);

        if (bean == null) {

            bean = handleSingleton(id);

        }

        return bean;
    }

    private Object handleSingleton(String id) {

        Object bean = createBean(id);

        if (isSingleton(id)) {

            this.beans.put(id, bean);

        }

        return bean;
    }

    private Object createBean(String id) {

        Element e = elementLoader.getElement(id);

        if (e == null) {

            try {
                throw new BeanCreateException("element not found" + id);
            } catch (BeanCreateException e1) {

                e1.printStackTrace();
            }

        }

        Object result = instance(e);

        System.out.println("創建bean" + id);

        System.out.println("該bean的對象是" + result);

        AutoWire autoWire = elementReader.getAutoWire(e);

        if (autoWire instanceof ByNameAutoWire) {

            // 使用名稱自動裝配
            autowireByName(result);

        } else if (autoWire instanceof NoAutoWire) {

            setterInject(result, e);

        }

        return null;
    }

    
    protected void createBeans(){
        
        Collection<Element> elements = elementLoader.getElements();
        
        for (Element element : elements) {
            
            boolean lazy = elementReader.isLazy(element);
            
            if (!lazy) {
                
                String id = element.attributeValue("id");
                
                Object bean = this.getBean(id);
                
                if (bean==null) {
                    
                    handleSingleton(id);
                    
                }
                
            }
            
        }
        
    }
    
    private void setterInject(Object obj, Element e) {

        List<PropertyElement> properties = elementReader.getPropertyValue(e);

        Map<String, Object> propertiesMap = getPropertyArgs(properties);

        propertyHandler.setProperties(obj, propertiesMap);

    }

    private Map<String, Object> getPropertyArgs(List<PropertyElement> properties) {

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

        for (PropertyElement p : properties) {

            DataElement de = p.getDataElement();

            if (de instanceof RefElement) {

                result.put(p.getName(), this.getBean((String) de.getValue()));

            } else if (de instanceof ValueElement) {

                result.put(p.getName(), de.getValue());

            }

        }

        return result;
    }

    private void autowireByName(Object obj) {

        Map<String, Method> methods = propertyHandler.getSetterMethodsMap(obj);

        for (String s : methods.keySet()) {

            Element e = elementLoader.getElement(s);

            if (e == null)
                continue;

            Object bean = this.getBean(s);

            Method method = methods.get(s);

            propertyHandler.executeMethod(obj, bean, method);

        }

    }

    private Object instance(Element e) {

        String className = elementReader.getAttribute(e, "class");

        List<Element> constructorElements = elementReader.getConstructorElements(e);

        if (constructorElements.size() == 0) {

            return beanCreator.createBeanUseDefaultConstruct(className);

        } else {

            List<Object> args = getConstructArgs(e);

            return beanCreator.createBeanUseDefineConstruct(className, args);
        }

    }

    private List<Object> getConstructArgs(Element e) {

        List<DataElement> datas = elementReader.getConstructorValue(e);

        List<Object> result = new ArrayList<Object>();

        for (DataElement d : datas) {

            if (d instanceof ValueElement) {

                d = (ValueElement) d;

                result.add(d.getValue());

            } else if (d instanceof RefElement) {

                d = (RefElement) d;

                String refid = (String) d.getValue();

                result.add(this.getBean(refid));

            }
        }

        return result;
    }

    @Override
    public boolean containsBean(String id) {

        Element element = elementLoader.getElement(id);

        return element == null ? false : true;

    }

    @Override
    public boolean isSingleton(String id) {

        Element e = elementLoader.getElement(id);

        return elementReader.isSingleTon(e);
    }

}

}

九:總結

我們經過上面的代碼就完整實現了一個Ioc容器,其中從Document的創造,再到Element的創建,再到解析Element,然后設置我們的Bean創造器,再實現AppliacionContext,這一過程在編碼中是不可逆的,因為只有有了Document,才有Element,再然后才有解析,我們的方法進行下一步的解析都需要上層作為參數,只有這樣才能完整解析Spring配置文件。我詳細闡述了這一流程,其中參閱了不少資料,耗時一星期,希望大家細細體會其中的方法,尤其是方法之間的串聯與解析的思路。從中過我們看出Spring解析的原理,我們進一步深入理解Spring框架起到了很大的的作用。同時本篇博文只是起到一個拋磚引玉的作用,示范了一些特性。按照這樣的邏輯,我們可以舉一反三,像mybaits、Hibernate的配置文件,我們大概就可以知道是如何解析的了。比如mybatis的配置文件,里面的sql配置,如何去拼接sql,無非就是解析文檔,把標簽里面的內容拿出來,拼接成String,交給jdbc去運行,這就是編程中的舉一反三,所以這篇博文不僅僅局限於Spring,有更多的東西值得我們去思考,加深自己的理解。好了,本次講解就到這里,我們下篇再見,謝謝。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM