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

  • 相关阅读:
    Android Studio 2.3.1导出jar文件不能生成release解决办法
    AndroidStudio 3.0 生成jar包的方法
    Android Studio如何打jar包
    Android Studio 如何打JAR包(修订版)
    6款程序员必备的开源中文处理工具
    Qt5.8 下链接 Mysql 错误以及解决方法(无论 Mysql 是什么版本的,64 位 Qt 要用 64 位的 Mysql 驱动,32 位的 Qt 要用 32 位的Mysql 驱动)
    Go 语言如果按这样改进,能不能火过 Java?
    基于 CSP 的设计思想和 OOP 设计思想的异同
    DELPHI下多线程编程的几个思维误区(QDAC)
    如何使用表单
  • 原文地址:https://www.cnblogs.com/Snail-1174158844/p/9952337.html
Copyright © 2011-2022 走看看