spring的自定义schema

本文介绍如何使用Spring自定义Schema来解析XML配置文件,并通过具体示例展示了如何创建自定义的Namespace处理器及Bean定义解析器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.项目结构



2.代码


package com.alibaba.dubbo.demo.xml;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.w3c.dom.Element;

public class MyBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

	private Class<?> beanClass;

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

	@SuppressWarnings("rawtypes")
	protected Class getBeanClass(Element element) {
		return beanClass;
	}
	
	protected void doParse(Element element, BeanDefinitionBuilder bean) {
		String orderId = element.getAttribute("orderId");
		bean.addPropertyValue("orderId", orderId);

		String userId = element.getAttribute("userId");
		bean.addPropertyValue("userId", Integer.valueOf(userId));
	}
}

package com.alibaba.dubbo.demo.xml;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class MyNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
		registerBeanDefinitionParser("or", new MyBeanDefinitionParser(
				Order.class));
	}
}

package com.alibaba.dubbo.demo.xml;

public class Order {

	private Integer orderId;

	private String userId;

	public Integer getOrderId() {
		return orderId;
	}

	public void setOrderId(Integer orderId) {
		this.orderId = orderId;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	@Override
	public String toString() {
		return "Order [orderId=" + orderId + ", userId=" + userId + "]";
	}

}

package com.alibaba.dubbo.demo.xml;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class OrderXsdTest {

	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext(
				"xml_applicationContex.xml");
		Order order1 = (Order) ctx.getBean("order1");
		System.out.println(order1);
	}
}

3.配置文件

   order.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.myschema.com/schema/order"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans"
	targetNamespace="http://www.myschema.com/schema/order"
	elementFormDefault="qualified" attributeFormDefault="unqualified">
	<xsd:import namespace="http://www.springframework.org/schema/beans" />
	<xsd:element name="or">
		<xsd:complexType>
			<xsd:complexContent>
				<xsd:extension base="beans:identifiedType">
					<xsd:attribute name="orderId" type="xsd:integer">
						<xsd:annotation>
							<xsd:documentation>
								订单ID
							</xsd:documentation>
						</xsd:annotation>
					</xsd:attribute>
					<xsd:attribute name="userId" type="xsd:string">
						<xsd:annotation>
							<xsd:documentation>
								用户ID
							</xsd:documentation>
						</xsd:annotation>
					</xsd:attribute>
				</xsd:extension>
			</xsd:complexContent>
		</xsd:complexType>
	</xsd:element>
</xsd:schema>

   spring.handlers

http\://www.myschema.com/schema/order=com.alibaba.dubbo.demo.xml.MyNamespaceHandler

   spring.schemas

http\://www.myschema.com/schema/order.xsd=META-INF/order.xsd


   xml_applicationContex.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:order="http://www.myschema.com/schema/order"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
    http://www.myschema.com/schema/order http://www.myschema.com/schema/order.xsd">

	<order:or id="order1" orderId="1" userId="1111" ></order:or>

</beans>

4.代码分析

    执行main方法加载spring,当解析xml的节点的时候会做一个判断

public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext(
				"xml_applicationContex.xml");
		Order order1 = (Order) ctx.getBean("order1");
		System.out.println(order1);
	}

    org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader

    在解析xml_applicationContex.xml的时候触发该方法 

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //判断根节点是否是默认的命名空间http://www.springframework.org/schema/beans
        if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
            //获取所有的子节点
            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;
                    //查看该子节点的命名空间
                    String namespaceUri = ele.getNamespaceURI();
                    //如果是默认的命名空间 那么就走默认的解析方法
                    if (delegate.isDefaultNamespace(namespaceUri)) {
                        parseDefaultElement(ele, delegate);
                    }
                    //如果不是默认的命名空间 那么就走自定义的解析方法
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

    org.springframework.beans.factory.xml.BeanDefinitionParserDelegate

    进行自定义解析

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
                //获取自定义的schema的命名空间
                String namespaceUri = ele.getNamespaceURI();
                //获取自定义的namespace类
                NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

     org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver

     返回自己的handler类

public NamespaceHandler resolve(String namespaceUri) {
                //获取所有spring.handlers文件里的内容封装成一个map
                Map handlerMappings = getHandlerMappings();
                //通过命名空间获取namespace的类路径(spring.handlers配置的)
                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 = ClassUtils.forName(className, this.classLoader);
				if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
					throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
							"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
				}
                                //实例化自己的handler
                                NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
                                //调用自己的handler的init方法
                                namespaceHandler.init();
				handlerMappings.put(namespaceUri, namespaceHandler);
				return namespaceHandler;
			}
			catch (ClassNotFoundException ex) {
				throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
						namespaceUri + "] not found", ex);
			}
			catch (LinkageError err) {
				throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
						namespaceUri + "]: problem with handler class file or dependent class", err);
			}
		}
	}
     com.alibaba.dubbo.demo.xml.MyNamespaceHandler

     调用自己的handler类的init方法

    

@Override
	public void init() {
		registerBeanDefinitionParser("or", new MyBeanDefinitionParser(
				Order.class));
	}

    org.springframework.beans.factory.xml.NamespaceHandlerSupport

    通过该方法找到对应自定义的schema的类

   

private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
                //获取自定义的解析类
                BeanDefinitionParser parser = (BeanDefinitionParser) this.parsers.get(element.getLocalName());
		if (parser == null) {
			parserContext.getReaderContext().fatal(
					"Cannot locate BeanDefinitionParser for element [" + element.getLocalName() + "]", element);
		}
		return parser;
	}
    com.alibaba.dubbo.demo.xml.MyBeanDefinitionParser

    接着就调用自己的doParse方法

   

protected void doParse(Element element, BeanDefinitionBuilder bean) {
		String orderId = element.getAttribute("orderId");
		bean.addPropertyValue("orderId", orderId);

		String userId = element.getAttribute("userId");
		bean.addPropertyValue("userId", Integer.valueOf(userId));
	}

    接着就是把该类注入到了spring的容器里,可以通过getbean获取到该对象了

    就行main方法里的那样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值