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>
再次执行测试代码会报错: