spring IOC 之篇四:自定义标签的解析
对代码delegate.parseCustomElement(ele);进行深入分析
对于dubbo就是使用了spring自定义标签解析的功能特性。Spring自定 义标签解析的过程如下:
- 创建一个需要扩展的组件
- 定义一个XSD描述文件内容
- 创建一个类实现BeanDefinitionParser接口,用来解析XSD文件中的定义和组件中的定义
- 创建一个Handler组件,扩展自NamespaceHandlerSupport,目的是将组件注册到Spring容器
- 编写Spring.handlers和Spring.schemas文件
现在开始依据上面的步骤开始使用自定义标签解析
1.创建一个类用来接收配置文件中的属性
public class People { private String id; private String name; private Integer age; // 省略get/set方法
- 创建一个xsd文件描述xml语法约束
-
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://blog.csdn.net/cutesource/schema/people" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://blog.csdn.net/cutesource/schema/people" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xsd:import namespace="http://www.springframework.org/schema/beans" /> <xsd:element name="people"> <xsd:complexType> <xsd:complexContent> <xsd:extension base="beans:identifiedType"> <xsd:attribute name="name" type="xsd:string" /> <xsd:attribute name="age" type="xsd:int" /> </xsd:extension> </xsd:complexContent> </xsd:complexType> </xsd:element> </xsd:schema> 在xsd定义了age 和name属性,与people实体里面的属性一一对应
- 创建一个文件,实现BeanDefinitionParser接口,解析XSD和XML文件中的定义
package com.spring.test.parser; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.util.StringUtils; import org.w3c.dom.Element; import com.spring.test.pojo.People; public class PeopleBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { // Element对应的类 @Override protected Class getBeanClass(Element element) { return People.class; } // 从element中解析并提取对应元素 @Override protected void doParse(Element element, BeanDefinitionBuilder bean) { String name = element.getAttribute("name"); String age = element.getAttribute("age"); String id = element.getAttribute("id"); if (StringUtils.hasText(id)) { // 将提取的数据放入BeanDefinitionBuilder 中,待解析完成后放入统一注册到beanFactory bean.addPropertyValue("id", id); } if (StringUtils.hasText(name)) { bean.addPropertyValue("name", name); } if (StringUtils.hasText(age)) { bean.addPropertyValue("age", Integer.valueOf(age)); } } }
编写Spring.handlers和Spring.schemas文件
Spring.handlers
http://blog.csdn.net/cutesource/schema/people=com.spring.test.handler.MyNamespaceHandler
Spring.schemas
http://blog.csdn.net/cutesource/schema/people.xsd=META-INF/people.xsd
到这里自定义标签的各种配置就结束了,而Spring自定义标签解析的流程就是根据Spring.handlers和Spring.schemas定义的内容去找对应的handler和xsd,默认位置是 META-INF/下面
- 创建测试配置文件 引入自定义标签的解析的路径和名称空间
-
<?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:cutesource="http://blog.csdn.net/cutesource/schema/people" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://blog.csdn.net/cutesource/schema/people http://blog.csdn.net/cutesource/schema/people.xsd"> <cutesource:people /> </beans>
创建测试
-
public class CustomHandler { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("customer.xml"); People p = (People)ctx.getBean("people"); System.out.println(p.getId()); System.out.println(p.getName()); System.out.println(p.getAge()); }
控制台打印:
Init method after properties are set id : initIt---afterPropertiesSet
initIt---afterPropertiesSet
袁志俊
27 - 工程截图
了解了自定义标签的使用,接下来对源码进行分析
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { // 获取对应的命名空间 String namespaceUri = getNamespaceURI(ele); // 根据命名空间找到对应的NamespaceHandler NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } // 调用自定义的NamespaceHandler进行解析 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
主要分析: NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); 根据命名空间找到对应的NamespaceHandler
在readerContext初始化的时候,其属性NamespaceHandlerResolver已经被初始化为DefaultNamespaceHandlerResolver实例,我们直接调用DefaultNamespaceHandlerResolver的resolve方法即可。
public NamespaceHandler resolve(String namespaceUri) { // 获取所有已经配置的handler映射 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 = 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"); } // 初始化类 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); // 调用自定义的初始化方法 namespaceHandler.init(); // 将解析好的Handler 记录在缓存 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); } } }
继续进行handler.parse(ele, new ParserContext(this.readerContext, this, containingBd))的分析
/** * Locates the {@link BeanDefinitionParser} from the register implementations using * the local name of the supplied {@link Element}. */ private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { // 获取的名称为people 即localName为people String localName = parserContext.getDelegate().getLocalName(element); // 获取对应的解析器 即代码registerBeanDefinitionParser("people", new PeopleBeanDefinitionParser()); 注册的解析器 BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; }
解析方法的分析
@Override public final BeanDefinition parse(Element element, ParserContext parserContext) { AbstractBeanDefinition definition = parseInternal(element, parserContext); if (definition != null && !parserContext.isNested()) { try { String id = resolveId(element, definition, parserContext); if (!StringUtils.hasText(id)) { parserContext.getReaderContext().error( "Id is required for element '" + parserContext.getDelegate().getLocalName(element) + "' when used as a top-level tag", element); } String[] aliases = null; if (shouldParseNameAsAliases()) { String name = element.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(name)) { aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name)); } } // 将AbstractBeanDefinition转换为BeanDefinitionHolder并注册 BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases); registerBeanDefinition(holder, parserContext.getRegistry()); if (shouldFireEvents()) { // 需要通知监听器并处理 BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder); postProcessComponentDefinition(componentDefinition); parserContext.registerComponent(componentDefinition); } } catch (BeanDefinitionStoreException ex) { parserContext.getReaderContext().error(ex.getMessage(), element); return null; } } return definition; }
主要解析逻辑
AbstractBeanDefinition definition = parseInternal(element, parserContext)的处理
@Override protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); String parentName = getParentName(element); if (parentName != null) { builder.getRawBeanDefinition().setParentName(parentName); } // 获取自定义标签的中class,此时会调用自定义解析器,PeopleBeanDefinitionParser中的getBeanClass()方法 Class<?> beanClass = getBeanClass(element); if (beanClass != null) { builder.getRawBeanDefinition().setBeanClass(beanClass); } else { // 如果子类没有重写getBeanClass方法,则检查有没有重写getBeanClassName方法 String beanClassName = getBeanClassName(element); if (beanClassName != null) { builder.getRawBeanDefinition().setBeanClassName(beanClassName); } } builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); if (parserContext.isNested()) { // Inner bean definition must receive same scope as containing bean. // 如果存在父类,则调用父类的scope属性 builder.setScope(parserContext.getContainingBeanDefinition().getScope()); } if (parserContext.isDefaultLazyInit()) { // Default-lazy-init applies to custom bean definitions as well. // 是否配置延迟加载 builder.setLazyInit(true); } // 调用子类重写的parse方法 doParse(element, parserContext, builder); return builder.getBeanDefinition(); }