Spring源码解析-自定义标签解析
2017-01-19 15:36
597 查看
Demo
创建接收配置的POJO
元素的XSD文件
Handler处理
BeanDefinitionParser
springhandlers和springschemals
Test
源码解析
getNamespaceHandlerResolver-resolve
NamespaceHandler-parse
总结
上一篇beanfactory里面在解析xml文件的时候,默认namespace是bean的解析,其他的使用自定义的标签解析。
spring.schemals
注意这2个文件要放在META-INF下,要不把上面这些都打jar,要不META-INF放到class目录去,否则找不到。
注意添加,我的是Intellij,eclipse应该也有地方添加:
Intellij:
还是委托BeanDefinitionParserDelegate处理:
到这里获取到处理自定义标签的NamespaceHandler。
看下BeanDefinition的parser方法:
上面Demo里面我们继承的是AbstractSingleBeanDefinitionParser,提供了进一步的封装:
最主要的还是工具类BeanDefinitionBuilder利用Builder模式封装了BeanDefinition,提供了简单设置构造方法、属性的方法。
NamespaceHandler的init方法不一定要注册BeanDefinitionParser,可以注册个bean到spring里面,可以继承实现实例化前、实例化后、初始化前、初始化后处理器的方法,来拦截其他的bean注册,Aop就是这么处理的,当时看的时候还挺疑惑的,还感觉怎么不按常理出牌。
创建接收配置的POJO
元素的XSD文件
Handler处理
BeanDefinitionParser
springhandlers和springschemals
Test
源码解析
getNamespaceHandlerResolver-resolve
NamespaceHandler-parse
总结
上一篇beanfactory里面在解析xml文件的时候,默认namespace是bean的解析,其他的使用自定义的标签解析。
Demo
创建接收配置的POJO
public class RpcService implements Serializable{ // 协议名称 private String contact; // 服务名称 private String serviceName; // 服务实现 private String serviceImplName; public RpcService(){ } public String getContact() { return contact; } public void setContact(String contact) { this.contact = contact; } public String getServiceName() { return serviceName; } public void setServiceName(String serviceName) { this.serviceName = serviceName; } public String getServiceImpl() { return serviceImplName; } public void setServiceImplName(String serviceImplName) { this.serviceImplName = serviceImplName; } @Override public String toString() { return "RpcService{" + "contact='" + contact + '\'' + ", serviceName='" + serviceName + '\'' + ", serviceImplName='" + serviceImplName + '\'' + '}'; } }
public class UserInfoService { private String name = "xu"; private int age = 18; public UserInfoService(){} public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "UserInfoService{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
元素的XSD文件
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.qbb.com/schema/qbb" xmlns:tns="http://www.qbb.com/schema/qbb" elementFormDefault="qualified"> <element name="service-publish"> <complexType> <attribute name="id" type="string" default="" /> <attribute name="contact" type="string" default="" /> <attribute name="serviceName" type="string" default="" /> <attribute name="serviceImplName" type="string" default="" /> </complexType> </element> </schema>
Handler处理
public class RpcServiceNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("service-publish", new RpcServicePublishBeanDefinitionParser()); } }
BeanDefinitionParser
public class RpcServicePublishBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { @Override protected void doParse(Element element, BeanDefinitionBuilder builder) { String contact = element.getAttribute("contact"); String serviceName = element.getAttribute("serviceName"); String serviceImplName = element.getAttribute("serviceImplName"); if (StringUtils.hasText(contact)){ builder.addPropertyValue("contact", contact); } if (StringUtils.hasText(serviceName)){ builder.addPropertyValue("serviceName", serviceName); } if (StringUtils.hasText(serviceImplName)){ builder.addPropertyValue("serviceImplName", serviceImplName); } } @Override protected Class<?> getBeanClass(Element element) { return RpcService.class; } @Override protected String getBeanClassName(Element element) { return RpcService.class.getSimpleName(); } }
spring.handlers和spring.schemals
spring.handlershttp\://www.qbb.com/schema/qbb=qbb.rpc.RpcServiceNamespaceHandler
spring.schemals
http\://www.qbb.com/schema/qbb.xsd=META-INF/qbb-rpc.xsd
注意这2个文件要放在META-INF下,要不把上面这些都打jar,要不META-INF放到class目录去,否则找不到。
Test
<?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:context="http://www.springframework.org/schema/context" xmlns:rpc="http://www.qbb.com/schema/qbb" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.qbb.com/schema/qbb http://www.qbb.com/schema/qbb.xsd"> <rpc:service-publish id="userInfoService" contact="UserInfoCenter" serviceName="UserInfoQuery" serviceImplName="qbb.rpc.UserInfoService"/> </beans>
注意添加,我的是Intellij,eclipse应该也有地方添加:
Intellij:
public class MyBeanTest { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { BeanFactory ctx = new XmlBeanFactory(new ClassPathResource("spring.xml")); RpcService rpcService = ctx.getBean("userInfoService",RpcService.class); System.out.println(rpcService); String rpcServiceImplName = rpcService.getServiceImpl(); UserInfoService userInfoService = (UserInfoService)Class.forName(rpcServiceImplName).newInstance(); System.out.println(userInfoService); } }
源码解析
之前看beanfactory的解析的时候,解析标签的时候,会区分是默认的namespaces还是自定义的://DefaultBeanDefinitionDocumentReader protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // 默认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)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { //自定义标签 delegate.parseCustomElement(root); } }
还是委托BeanDefinitionParserDelegate处理:
public BeanDefinition parseCustomElement(Element ele) { return parseCustomElement(ele, null); } public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { // 获取uri String namespaceUri = getNamespaceURI(ele); // 根据uri获取处理handler NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } // 解析标签,返回对应的beanDefinition return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
getNamespaceHandlerResolver()-resolve
//DefaultNamespaceHandlerResolver //DefaultNamespaceHandlerResolver public NamespaceHandler resolve(String namespaceUri) { //获取META-INF/spring.handlers所有配置的namespace的handler Map<String, Object> handlerMappings = getHandlerMappings(); //获取到自定义标签解析的handler 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); //如果不是NamespaceHandle的子类的话,抛异常 if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); } //实例化NamespaceHandler NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); //调用初始化注册beanDefinitionParser 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); } } } //获取META-INF/spring.handlers所有配置的namespace的handler private Map<String, Object> getHandlerMappings() { if (this.handlerMappings == null) { synchronized (this) { if (this.handlerMappings == null) { try { //handlerMappingsLocation默认是META-INF/spring.handlers Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); if (logger.isDebugEnabled()) { logger.debug("Loaded NamespaceHandler mappings: " + mappings); } Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(); CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); this.handlerMappings = handlerMappings; } catch (IOException ex) { throw new IllegalStateException( "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex); } } } } return this.handlerMappings; }
到这里获取到处理自定义标签的NamespaceHandler。
NamespaceHandler-parse
//NamespaceHandlerSupport public BeanDefinition parse(Element element, ParserContext parserContext) { return findParserForElement(element, parserContext).parse(element, parserContext); } // 获取对应的beanDefinitionParse来解析对应的标签 private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { String localName = parserContext.getDelegate().getLocalName(element); //this.parsers需要我们在NamespaceHandler的init注册进来 BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; } //NamespaceHandler的init注册自定义标签的beanDefinitionParse protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) { this.parsers.put(elementName, parser); }
看下BeanDefinition的parser方法:
//AbstractBeanDefinitionParser public final BeanDefinition parse(Element element, ParserContext parserContext) { //子类继承覆盖parseInternal完成解析BeanDefinition AbstractBeanDefinition definition = parseInternal(element, parserContext); if (definition != null && !parserContext.isNested()) { try { //bean的id,可以通过覆盖shouldGenerateId返回true,选择spring自己生成,要不然就自定义标签里面自己提供一个id 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 = new String[0]; String name = element.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(name)) { aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name)); } BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases); //注册beanDefinition到spring 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; }
上面Demo里面我们继承的是AbstractSingleBeanDefinitionParser,提供了进一步的封装:
//AbstractSingleBeanDefinitionParser public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser { @Override protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); String parentName = getParentName(element); if (parentName != null) { builder.getRawBeanDefinition().setParentName(parentName); } //子类覆盖getBeanClass返回beanclass Class<?> beanClass = getBeanClass(element); if (beanClass != null) { builder.getRawBeanDefinition().setBeanClass(beanClass); } else { //子类覆盖getBeanClassName返回beanClassName 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. builder.setScope(parserContext.getContainingBeanDefinition().getScope()); } if (parserContext.isDefaultLazyInit()) { // Default-lazy-init applies to custom bean definitions as well. builder.setLazyInit(true); } doParse(element, parserContext, builder); return builder.getBeanDefinition(); } protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { doParse(element, builder); } //需要子类覆盖完成标签解析 protected void doParse(Element element, BeanDefinitionBuilder builder) { } }
最主要的还是工具类BeanDefinitionBuilder利用Builder模式封装了BeanDefinition,提供了简单设置构造方法、属性的方法。
总结
自定义的标签的扩展还是挺牛,看到好多地方用到,例如:通过自定义实现rpc的服务发现注册到zk;NamespaceHandler的init方法不一定要注册BeanDefinitionParser,可以注册个bean到spring里面,可以继承实现实例化前、实例化后、初始化前、初始化后处理器的方法,来拦截其他的bean注册,Aop就是这么处理的,当时看的时候还挺疑惑的,还感觉怎么不按常理出牌。
相关文章推荐
- Spring源码解析之自定义标签的解析
- Spring源码阅读-- 解析自定义命名空间的标签
- Spring源码解析-自定义标签解析
- spring 源码探索--xml的自定义标签解析
- 6.2 dubbo在spring中自定义xml标签源码解析
- spring源码剖析(四)自定义标签解析流程
- spring源码剖析(四)自定义标签解析流程
- spring源码(9)自定义标签与自定义标签的解析
- Spring源码解密之自定义标签与解析
- spring源码剖析(四)自定义标签解析流程
- Spring源码解析:自定义标签的解析过程
- Dubbo源码分析(三):自定义Schema--基于Spring可扩展Schema提供自定义配置支持(spring配置文件中 配置标签支持)
- spring源码(7)alias标签的解析
- Spring源码情操陶冶-自定义节点的解析
- spring源码(6)bean标签其他子标签的解析
- spring源码学习之:xml配置文件标签自定义
- spring源码附录(8)import、beans标签的解析
- Spring源码解析之一 ------ 默认标签的解析注册(IOC的第一步)
- spring 3源码解析之如何解析"import", "alias", "bean"标签
- Spring4.3.x 浅析xml配置的解析过程(5)——解析自定义命名空间的标签