zoukankan      html  css  js  c++  java
  • 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,有更多的东西值得我们去思考,加深自己的理解。好了,本次讲解就到这里,我们下篇再见,谢谢。

  • 相关阅读:
    TCP源码—连接建立
    TCP系列02—连接管理—1、三次握手与四次挥手
    TCP系列01—概述及协议头格式
    ubuntu软件管理apt与dpkg
    318. Maximum Product of Word Lengths
    317. Shortest Distance from All Buildings
    316. Remove Duplicate Letters
    315. Count of Smaller Numbers After Self
    314. Binary Tree Vertical Order Traversal
    313. Super Ugly Number
  • 原文地址:https://www.cnblogs.com/wyq178/p/6843502.html
Copyright © 2011-2022 走看看