Spring IOC 之 xml配置解析过程(BeanDefinition)源码

1、首先从简单使用开始

spring xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
    >

   <bean id ="person" class="org.spring.Person">
      <property name="name" value="zhangsan"></property>
   </bean>

</beans>

java 代码:

public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

测试代码:

ClassPathResource resource = new ClassPathResource("spring-ioc.xml");
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(resource);

Person person = beanFactory.getBean(Person.class);
System.out.println(person);

运行结果:

=======================从源码层面简单分析一下逻辑===================

一个简单的Bean工厂实现有以下几个步骤:
  • 步骤1:创建BeanFactory工厂类,用来缓存生成的BeanDefinition和bean实例
  • 步骤2:创建XmlBeanDefinitionReader类,解析xml资源,创建Document对象
  • 步骤3:创建BeanDefinitionDocumentReader类,解析Document对象
  • 步骤4:创建BeanDefinitionParserDelegate类, 专门解析<bean>元素的Element对象以及自定义标签元素(例如:<dubbo:server> <dubbo:service>),自定义标签解析任务会委托给NamespaceHandler处理
  • 步骤5: 创建NamespaceHandler类,处理自定义的命名空间;创建BeanDefinitionParser类,处理自定义的标签元素
===========根据上面步骤自己实现一版简化版的Bean工厂容器===================
准备阶段:

1、xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://www.myspringtest.org/schema/dubbo/spring-dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	   http://www.myspringtest.org/schema/dubbo/spring-dubbo http://www.myspringtest.org/schema/dubbo/spring-dubbo.xsd">

    <bean id="person" class="org.spring.xml.bean.Person">
        <property name="name" value="zhangsan"></property>
    </bean>

    <dubbo:server url="http://localhost" port="8080"></dubbo:server>
    <dubbo:service serviceName="Login" methodName="auth"></dubbo:service>
</beans>

2、准备三个bean类

public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Server {
    private String url;
    private String port;

    public void setUrl(String url) {
        this.url = url;
    }

    public void setPort(String port) {
        this.port = port;
    }
}
public class Service {
    private String serviceName;
    private String methodName;

    public String getServiceName() {
        return serviceName;
    }

    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }
}

编码阶段:

1、定义一个简化版的BeanDefinition,<bean>元素解析后的内容都被封装成BeanDefinition

public class BeanDefinition {

    //装载bean的Class
    private Class<?> beanClass;

    //装载bean的属性名称和属性值,简单起见仅支持String类型字段
    //在spring IOC中用MutablePropertyValues装载属性
    private Map<String, Object> propertyValueMap =  new HashMap<String, Object>(0);

    public void setBeanClass(Class<?> beanClass) {
        this.beanClass = beanClass;
    }

    public Class<?> getBeanClass() throws IllegalStateException {
        return this.beanClass;
    }

    public void addPropertyValue(String name, Object value) {
        propertyValueMap.put(name, value);
    }

    public Map<String, Object> getPropertyValueMap() {
        return propertyValueMap;
    }
}

2、便于程序处理,定义一个BeanDefinition携带者类==》BeanDefinitionHolder

public class BeanDefinitionHolder {
    //装载bean的定义信息
    private final BeanDefinition beanDefinition;

    //bean的名称
    private final String beanName;


    public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName) {
        this.beanDefinition = beanDefinition;
        this.beanName = beanName;
    }

    public BeanDefinition getBeanDefinition() {
        return beanDefinition;
    }

    public String getBeanName() {
        return beanName;
    }
}

3、定义一个BeanDefinitionRegistry接口,用于注册BeanDefinition

public interface BeanDefinitionRegistry {

    //注册beanDefinition
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
}

4、定义一个简单的Bean工厂类:SimpleBeanFactory,用来缓存BeanDefinition、创建Bean实例以及缓存生成的单例Bean实例

public class SimpleBeanFactory implements BeanDefinitionRegistry {

    //用来缓存生成的beanDefinition
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);

    //用来缓存生成的bean实例
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);

    //---------------------------------------------------------------------
    // Implementation of BeanDefinitionRegistry interface
    //---------------------------------------------------------------------
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }

    //获取bean对象,简单模拟创建bean的过程
    public Object getBean(String beanName) {
        if(singletonObjects.containsKey(beanName)) {
            return singletonObjects.get(beanName);
        } else {
            if(beanDefinitionMap.containsKey(beanName)) {
                BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
                Class<?> beanClass = beanDefinition.getBeanClass();
                try {
                    //实例化bean对象
                    Object obj = beanClass.newInstance();
                    singletonObjects.put(beanName, obj);

                    //调用setXXX方法,为bean实例属性赋值
                    Map<String, Object> propertyValueMap = beanDefinition.getPropertyValueMap();
                    for (String propertyName : propertyValueMap.keySet()) {
                        Object val = propertyValueMap.get(propertyName);
                        String setMethodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
                        Method method = beanClass.getDeclaredMethod(setMethodName, new Class[]{String.class});
                        method.invoke(obj, String.valueOf(val));
                    }
                    return obj;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }
}

bean工厂类SimpleBeanFactory实现了BeanDefinitionRegistry,所以SimpleBeanFactory也是BeanDefinition注册中心,同时根据BeanDefinition可以创建bean实例为上层服务使用。

5、定义类XmlBeanDefinitionReader,用来读取xml资源文件,创建生成Document对象。

public class XmlBeanDefinitionReader {

    private final BeanDefinitionRegistry registry;

    private NamespaceHandlerResolver namespaceHandlerResolver;

    //构造函数
    //此处的BeanDefinitionRegistry其实是BeanFactory,因为SimpleBeanFactory实现了BeanDefinitionRegistry
    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }

    //流程节点1
    //加载xml资源
    public void loadBeanDefinitions(InputSource inputSource) throws Exception {
        //加载xml资源,转为为Document对象
        Document doc = this.loadDocument(inputSource);
        //流程节点2
        this.registerBeanDefinitions(doc);
    }

    //流程节点2
    //解析xml转化为BeanDefinition入口
    public void registerBeanDefinitions(Document doc) throws Exception {
        BeanDefinitionDocumentReader documentReader = new BeanDefinitionDocumentReader();
        //流程节点3
        //解析工作交由BeanDefinitionDocumentReader处理
        documentReader.registerBeanDefinitions(doc, createReaderContext());
    }

    //==============================以下为辅助功能代码=====================================================

    /**
     * 创建xml上下文类
     *
     * @return
     */
    protected XmlReaderContext createReaderContext() {
        if (this.namespaceHandlerResolver == null) {
            this.namespaceHandlerResolver = new NamespaceHandlerResolver();
        }
        return new XmlReaderContext(this, this.namespaceHandlerResolver);
    }

    /**
     * 设置xml命名空间处理类
     * @param namespaceHandlerResolver
     */
    public void setNamespaceHandlerResolver(NamespaceHandlerResolver namespaceHandlerResolver) {
        this.namespaceHandlerResolver = namespaceHandlerResolver;
    }

    /**
     * 获取BeanDefinition注册中心,其实就是BeanFactory,BeanFactory实现了BeanDefinitionRegistry
     * @return
     */
    public final BeanDefinitionRegistry getRegistry() {
        return this.registry;
    }

    /**
     * 将xml资源文件解析成Document对象
     * @param inputSource
     * @return
     * @throws Exception
     */
    public Document loadDocument(InputSource inputSource) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        //开启/关闭用于支持 XML 1.0 的名称空间处理,如果关闭会导致Node无法获取命名空间
        factory.setNamespaceAware(true);
        //开启/关闭验证,开启需要验证模板文件
        factory.setValidating(false);
        factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");

        DocumentBuilder docBuilder = factory.newDocumentBuilder();

        docBuilder.setEntityResolver(new DelegatingEntityResolver(this.getClass().getClassLoader()));

        //xml解析过程中发生错误交由SimpleSaxErrorHandler处理
        docBuilder.setErrorHandler(new SimpleSaxErrorHandler());
        Document document = docBuilder.parse(inputSource);
        return document;
    }

    /**
     * xml解析错误处理类
     */
    private static class SimpleSaxErrorHandler implements ErrorHandler {

        public SimpleSaxErrorHandler() {
        }

        public void warning(SAXParseException ex) throws SAXException {
            System.out.printf("Ignored XML validation warning %s", ex);
        }

        public void error(SAXParseException ex) throws SAXException {
            throw ex;
        }

        public void fatalError(SAXParseException ex) throws SAXException {
            throw ex;
        }
    }
}

6、定义类BeanDefinitionDocumentReader,用来处理Document对象。

public class BeanDefinitionDocumentReader {

    public static final String BEAN_ELEMENT = "bean";

    private XmlReaderContext readerContext;

    //流程节点3
    //处理xml Document对象入口
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) throws Exception {
        this.readerContext = readerContext;
        //获取xml根元素<beans>对象
        Element root = doc.getDocumentElement();

        //流程节点4
        //对Document对象根节点元素<beans>处理入口
        this.doRegisterBeanDefinitions(root);
    }

    //流程节点4
    //对Document对象根节点元素<beans>处理入口
    protected void doRegisterBeanDefinitions(Element root) throws Exception {
        //创建BeanDefinitionParserDelegate对象,后面对<bean>元素的处理工作交由它处理
        BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(this.readerContext);

        //流程节点5
        //对Document对象根节点元素<beans>下面的子元素进行处理的入口
        this.parseBeanDefinitions(root, delegate);
    }

    //流程节点5
    //对Document对象根节点元素<beans>下面的子元素进行处理的入口
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) throws Exception {
        //根据元素Node对象上URI获取命名空间名称,判断命名空间是否默认命名空间
        //默认命名空间:"http://www.springframework.org/schema/beans"
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    //判断子元素的命名空间是否默认命名空间
                    if (delegate.isDefaultNamespace(ele)) {
                        //流程节点6
                        parseDefaultElement(ele, delegate);
                    } else {
                        //如果不是默认命名空间,则认为是自定义标签元素
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            //如果不是默认命名空间,则认为是自定义标签元素,根元素有可能不是<beans>
            delegate.parseCustomElement(root);
        }
    }

    //流程节点6
    //解析<beans>元素的子元素
    public void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) throws Exception {
        //作为简单样例,认为<beans>元素下面只有<bean>元素
        if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            //流程节点7
            //解析元素<bean>
            processBeanDefinition(ele, delegate);
        }
    }

    //流程节点7
    //解析元素<bean>
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) throws Exception {
        //流程节点8 核心流程
        //解析元素<bean>的工作委托给BeanDefinitionParserDelegate处理
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            String beanName = bdHolder.getBeanName();
            //将生成的BeanDefinition注册到bean工厂中
            readerContext.getRegistry().registerBeanDefinition(beanName, bdHolder.getBeanDefinition());
        }
    }
}

7、定义类BeanDefinitionParserDelegate,用来处理<bean>元素和自定义标签元素,例如<dubbo:server>

public class BeanDefinitionParserDelegate {
    public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";

    public static final String ID_ATTRIBUTE = "id";
    public static final String CLASS_ATTRIBUTE = "class";

    public static final String PROPERTY_ELEMENT = "property";
    public static final String NAME_ATTRIBUTE = "name";
    public static final String VALUE_ATTRIBUTE = "value";

    private final XmlReaderContext readerContext;

    public BeanDefinitionParserDelegate(XmlReaderContext readerContext) {
        this.readerContext = readerContext;;
    }

    //流程节点6-分支1-节点3 核心流程
    //对<bean>元素进行解析
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) throws ClassNotFoundException {
        String id = ele.getAttribute(ID_ATTRIBUTE);
        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }

        String beanName = id;

        BeanDefinition beanDefinition = new BeanDefinition();
        if (className != null) {
            beanDefinition.setBeanClass(Class.forName(className));
        }

        //解析<property>元素
        parsePropertyElements(ele, beanDefinition);

        return new BeanDefinitionHolder(beanDefinition, beanName);
    }

    ///流程节点6-分支2-节点1 核心流程
    //对自定义标签元素进行解析
    public BeanDefinition parseCustomElement(Element ele) {
        String namespaceUri = getNamespaceURI(ele);
        //根据命名空间名称获取命名空间处理器,参考NamespaceHandlerResolver
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            return null;
        }

        //核心流程,自定义标签解析工作交由各个命名空间处理器自己处理,参考MyNamespaceHanlder
        return handler.parse(ele, new ParserContext(this.readerContext, this));
    }

    //解析<property>元素
    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
        NodeList nl = beanEle.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
                parsePropertyElement((Element) node, bd);
            }
        }
    }

    //解析<property>元素
    public void parsePropertyElement(Element ele, BeanDefinition bd) {
        String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
        if (!StringUtils.hasLength(propertyName)) {
            return;
        }
        Object val = ele.getAttribute(VALUE_ATTRIBUTE);
        bd.addPropertyValue(propertyName, val);
    }

    //===============================以下为辅助功能代码=============================================

    //检查node的URI命名空间是否为"http://www.springframework.org/schema/beans"
    public boolean isDefaultNamespace(Node node) {
        return isDefaultNamespace(getNamespaceURI(node));
    }

    //检查node的URI命名空间是否为"http://www.springframework.org/schema/beans"
    public boolean isDefaultNamespace(String namespaceUri) {
        return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
    }

    //获取node的URI
    public String getNamespaceURI(Node node) {
        return node.getNamespaceURI();
    }

    public boolean nodeNameEquals(Node node, String desiredName) {
        return desiredName.equals(node.getNodeName()) || desiredName.equals(getLocalName(node));
    }

    public String getLocalName(Node node) {
        return node.getLocalName();
    }

    private boolean isCandidateElement(Node node) {
        return (node instanceof Element && (isDefaultNamespace(node) || !isDefaultNamespace(node.getParentNode())));
    }
}

8、定义类NamespaceHandlerResolver,用来从META-INF/spring.handlers加载命名空间处理器

public class NamespaceHandlerResolver {

    public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";

    private volatile Map<String, Object> handlerMappings;

    /**
     * 根据命名空间名称获取命名空间处理类对象
     * @param namespaceUri
     * @return
     * @throws Exception
     */
    public NamespaceHandler resolve(String namespaceUri) {
        Map<String, Object> handlerMappings = getHandlerMappings();
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        } else if (handlerOrClassName instanceof NamespaceHandler) { //同一个命名空间被多次调用
            return (NamespaceHandler) handlerOrClassName;
        } else {
            String className = (String) handlerOrClassName;
            try {
                Class<?> handlerClass = Class.forName(className);
                if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                    throw new Exception("处理命名空间[" + namespaceUri + "]的类 [" + className + "] 需要实现接口[NamespaceHandler]");
                }
                NamespaceHandler namespaceHandler = (NamespaceHandler) handlerClass.newInstance();
                namespaceHandler.init();
                handlerMappings.put(namespaceUri, namespaceHandler);
                return namespaceHandler;
            } catch (Exception err) {
                err.printStackTrace();
            }
            return null;
        }
    }

    //从Properties资源文件中加载
    //从类路径下加载META-INF/spring.handlers,value为命名空间处理器
    private Map<String, Object> getHandlerMappings() {
        if (this.handlerMappings == null) {
            synchronized (this) {
                if (this.handlerMappings == null) {
                    try {
                        Properties mappings = PropertiesUtils.loadAllProperties(DEFAULT_HANDLER_MAPPINGS_LOCATION);
                        Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
                        PropertiesUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                        this.handlerMappings = handlerMappings;
                    }
                    catch (IOException ex) {
                        throw new IllegalStateException(ex);
                    }
                }
            }
        }
        return this.handlerMappings;
    }

    //Properties资源文件工具类
    private static class PropertiesUtils {

        /**
         * 加载Properties资源文件
         */
        public static Properties loadAllProperties(String resourceName) throws IOException {
            Enumeration<URL> urls = ClassLoader.getSystemResources(resourceName);
            Properties props = new Properties();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                URLConnection con = url.openConnection();
                InputStream is = con.getInputStream();
                try {
                    props.load(is);
                }
                finally {
                    is.close();
                }
            }
            return props;
        }

        /**
         * 将Properties属性值对追加到Map中
         * @param props
         * @param map
         */
        public static void mergePropertiesIntoMap(Properties props, Map map) {
            if (null == props || null == map) {
                return;
            }

            for (Enumeration en = props.propertyNames(); en.hasMoreElements();) {
                String key = (String) en.nextElement();
                Object value = props.getProperty(key);
                if (value == null) {
                    value = props.get(key);
                }
                map.put(key, value);
            }
        }
    }
}
NamespaceHandlerResolver由XmlBeanDefinitionReader实例化,然后传递给BeanDefinitionDocumentReader,最后传递给BeanDefinitionParserDelegate。
NamespaceHandlerResolver被封装在XmlReaderContext中,中间都是通过XmlReaderContext进行层层传递的。

XmlBeanDefinitionReader===[XmlReaderContext(NamespaceHandlerResolver)]===》BeanDefinitionDocumentReader===[XmlReaderContext(NamespaceHandlerResolver)]===》BeanDefinitionParserDelegate

spring.handlers文件配置:
http\://www.myspringtest.org/schema/dubbo/spring-dubbo=org.spring.xml.custom.MyNamespaceHanlder
自定义标签元素相关的类:
public interface NamespaceHandler {
    void init();

    BeanDefinition parse(Element element, ParserContext parserContext);
}
public class MyNamespaceHanlder implements NamespaceHandler {

    private final Map<String, BeanDefinitionParser> parsers = new HashMap<>();

    @Override
    public void init() {
        this.parsers.put("server", new ServerBeanDefinitionParser());
        this.parsers.put("service", new ServiceBeanDefinitionParser());
    }

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        return this.findParserForElement(element, parserContext).parse(element, parserContext);
    }

    private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
        String localName = parserContext.getDelegate().getLocalName(element);
        BeanDefinitionParser parser = this.parsers.get(localName);
        return parser;
    }
}

public interface BeanDefinitionParser {
    //解析自定义标签元素
    BeanDefinition parse(Element element, ParserContext parserContext);
}
public class ServerBeanDefinitionParser implements BeanDefinitionParser {

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        String url = element.getAttribute("url");
        String port = element.getAttribute("port");

        BeanDefinition bd = new BeanDefinition();
        bd.setBeanClass(Server.class);

        bd.addPropertyValue("url", url);
        bd.addPropertyValue("port", port);

        parserContext.getRegistry().registerBeanDefinition("dubboServer", bd);
        return bd;
    }
}
public class ServiceBeanDefinitionParser implements BeanDefinitionParser {

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        String serviceName = element.getAttribute("serviceName");
        String methodName = element.getAttribute("methodName");

        BeanDefinition bd = new BeanDefinition();
        bd.setBeanClass(Service.class);

        bd.addPropertyValue("serviceName", serviceName);
        bd.addPropertyValue("methodName", methodName);

        parserContext.getRegistry().registerBeanDefinition("dubboService", bd);
        return bd;
    }
}

测试代码:

ClassPathResource resource = new ClassPathResource("spring-simple.xml");

SimpleBeanFactory beanFactory = new SimpleBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new InputSource(resource.getInputStream()));

Person person = (Person) beanFactory.getBean("person");
System.out.println(person);

person = (Person) beanFactory.getBean("person");
System.out.println(person);

Server server = (Server) beanFactory.getBean("dubboServer");
System.out.println(server);

Service service = (Service) beanFactory.getBean("dubboService");
System.out.println(service);

执行结果:

在spring解析xml过程中还有一个重要工作就是验证xml文件的合法性,一个标准的xml文件每个元素和属性都是有意义的而不是随便乱写的

在XmlBeanDefinitionReader类中创建Document对象时有如下代码:

public Document loadDocument(InputSource inputSource) throws Exception {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    //开启/关闭用于支持 XML 1.0 的名称空间处理,如果关闭会导致Node无法获取命名空间
    factory.setNamespaceAware(true);
    //开启/关闭验证,开启需要验证模板文件
    factory.setValidating(false);
    factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");

    DocumentBuilder docBuilder = factory.newDocumentBuilder();

    //docBuilder.setEntityResolver(entityResolver);
    docBuilder.setEntityResolver(new DelegatingEntityResolver(this.getClass().getClassLoader()));

    //xml解析过程中发生错误交由SimpleSaxErrorHandler处理
    docBuilder.setErrorHandler(new SimpleSaxErrorHandler());
    Document document = docBuilder.parse(inputSource);
    return document;
}

factory.setValidating(true)开启验证模式,设置 docBuilder.setEntityResolver(entityResolver)。

需要定义一个类实现接口EntityResolver,spring中EntityResolver默认实现是DelegatingEntityResolver

DelegatingEntityResolver类:

public class DelegatingEntityResolver implements EntityResolver {

    /** Suffix for DTD files */
    public static final String DTD_SUFFIX = ".dtd";

    /** Suffix for schema definition files */
    public static final String XSD_SUFFIX = ".xsd";

    //DTD验证模式
    private final EntityResolver dtdResolver;

    //XSD验证模式
    private final EntityResolver schemaResolver;

    //构造函数
    public DelegatingEntityResolver(ClassLoader classLoader) {
        this.dtdResolver = new BeansDtdResolver();
        this.schemaResolver = new PluggableSchemaResolver(classLoader);
    }

    //构造函数
    public DelegatingEntityResolver(EntityResolver dtdResolver, EntityResolver schemaResolver) {
        this.dtdResolver = dtdResolver;
        this.schemaResolver = schemaResolver;
    }

    //核心流程方法:根据systemId判断分支
    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        if (systemId != null) {
            if (systemId.endsWith(DTD_SUFFIX)) { //DTD验证模式
                return this.dtdResolver.resolveEntity(publicId, systemId);
            }
            else if (systemId.endsWith(XSD_SUFFIX)) { //XSD验证模式
                return this.schemaResolver.resolveEntity(publicId, systemId);
            }
        }
        return null;
    }
}

以XSD验证模式分析:PluggableSchemaResolver

public class PluggableSchemaResolver implements EntityResolver {

    //spring.schemas存放路径
    public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";
    
    private final ClassLoader classLoader;

    private final String schemaMappingsLocation;

    //缓存存储schema映射
    private volatile Map<String, String> schemaMappings;


    //构造函数
    public PluggableSchemaResolver(ClassLoader classLoader) {
        this.classLoader = classLoader;
        this.schemaMappingsLocation = DEFAULT_SCHEMA_MAPPINGS_LOCATION;
    }

    //构造函数
    public PluggableSchemaResolver(ClassLoader classLoader, String schemaMappingsLocation) {
        this.classLoader = classLoader;
        this.schemaMappingsLocation = schemaMappingsLocation;
    }

    //根据systemId获取验证XSD文件资源
    public InputSource resolveEntity(String publicId, String systemId) throws IOException {
        if (systemId != null) {
            String resourceLocation = getSchemaMappings().get(systemId);
            if (resourceLocation != null) {
                Resource resource = new ClassPathResource(resourceLocation, this.classLoader);
                try {
                    InputSource source = new InputSource(resource.getInputStream());
                    source.setPublicId(publicId);
                    source.setSystemId(systemId);
                    return source;
                }
                catch (FileNotFoundException ex) {
                }
            }
        }
        return null;
    }

    /**
     * 从类路径META-INF/spring.schemas加载Schema映射
     */
    private Map<String, String> getSchemaMappings() {
        if (this.schemaMappings == null) {
            synchronized (this) {
                if (this.schemaMappings == null) {
                    try {
                        Properties mappings =
                                PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation, this.classLoader);
                        Map<String, String> schemaMappings = new ConcurrentHashMap<String, String>(mappings.size());
                        CollectionUtils.mergePropertiesIntoMap(mappings, schemaMappings);
                        this.schemaMappings = schemaMappings;
                    }
                    catch (IOException ex) {
                        throw new IllegalStateException(
                                "Unable to load schema mappings from location [" + this.schemaMappingsLocation + "]", ex);
                    }
                }
            }
        }
        return this.schemaMappings;
    }
}

自定义的XSD验证文件:spring-dubbo.xsd

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<xsd:schema xmlns="http://www.myspringtest.org/schema/dubbo/spring-dubbo"
		xmlns:xsd="http://www.w3.org/2001/XMLSchema"
		targetNamespace="http://www.myspringtest.org/schema/dubbo/spring-dubbo">

	<xsd:element name="server">
		<xsd:complexType>
			<xsd:attribute name="url" type="xsd:string"/>
			<xsd:attribute name="port" type="xsd:string"/>
		</xsd:complexType>
	</xsd:element>

	<xsd:element name="service">
		<xsd:complexType>
			<xsd:attribute name="serviceName" type="xsd:string"/>
			<xsd:attribute name="methodName" type="xsd:string"/>
		</xsd:complexType>
	</xsd:element>
</xsd:schema>
自定义的spring.schemas配置,需放到类路径META-INF/spring.schemas
http\://www.myspringtest.org/schema/dubbo/spring-dubbo.xsd=META-INF/schema/spring-dubbo.xsd
再次执行测试代码:
ClassPathResource resource = new ClassPathResource("spring-simple.xml");

SimpleBeanFactory beanFactory = new SimpleBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new InputSource(resource.getInputStream()));

Person person = (Person) beanFactory.getBean("person");
System.out.println(person);

person = (Person) beanFactory.getBean("person");
System.out.println(person);

Server server = (Server) beanFactory.getBean("dubboServer");
System.out.println(server);

Service service = (Service) beanFactory.getBean("dubboService");
System.out.println(service);
执行结果:

假如将<dubbo:service>属性serviceName改为serviceName1

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://www.myspringtest.org/schema/dubbo/spring-dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	   http://www.myspringtest.org/schema/dubbo/spring-dubbo http://www.myspringtest.org/schema/dubbo/spring-dubbo.xsd">

    <bean id="person" class="org.spring.xml.bean.Person">
        <property name="name" value="zhangsan"></property>
    </bean>

    <dubbo:server url="http://localhost" port="8080"></dubbo:server>
    <dubbo:service serviceName1="Login" methodName="auth"></dubbo:service>
</beans>

再次执行测试代码会报错:

  • 31
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值