spring jaxb_自定义Spring命名空间使JAXB变得更容易

spring jaxb

首先,让我大声说一下: Spring不再是XML繁重的了 。 实际上,如今,您可以使用大量注释, Java配置和Spring Boot来编写几乎没有XML或根本没有XML的Spring应用程序。 认真地停止谈论Spring和XML,这已经成为过去。

话虽这么说,您可能仍然出于以下几个原因而使用XML:您受困于旧代码库,出于其他原因选择了XML,或者将Spring用作某些框架/平台的基础。 最后一种情况实际上很常见,例如Mule ESB和ActiveMQ在下面使用Spring来连接它们的依赖项。 而且,Spring XML是他们配置框架的方式。 但是,使用纯Spring <bean/>配置消息代理或企业服务总线会很麻烦且冗长。 幸运的是,Spring支持编写可嵌入标准Spring配置文件中的自定义名称空间 。 这些自定义的XML代码片段在运行时进行了预处理,并且可以以简洁明快的外观(在XML允许的范围内)一次注册许多bean定义。 从某种意义上说,自定义名称空间就像在运行时扩展为多个bean定义的宏。

为了让您了解我们的目标,请想象一个具有多个业务实体的标准“企业”应用程序。 对于每个实体,我们定义三个几乎相同的bean:存储库,服务和控制器。 它们始终以相似的方式进行布线,只是细节有所不同。 首先,我们的Spring XML看起来像这样(我正在粘贴带有缩略图的屏幕截图,以免引起您的注意,它巨大且huge肿): XML文件

这是一个“分层”的体系结构,因此我们将称为onion的自定义命名空间-因为洋葱具有层次性 -并且因为以这种方式设计的系统使我哭泣。 在本文结束时,您将学习如何将这堆XML折叠为:

<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns:b="http://www.springframework.org/schema/beans"xmlns="http://nurkiewicz.blogspot.com/spring/onion/spring-onion.xsd"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.xsdhttp://nurkiewicz.blogspot.com/spring/onion/spring-onion.xsd http://nurkiewicz.blogspot.com/spring/onion/spring-onion.xsd"><b:bean id="convertersFactory" class="com.blogspot.nurkiewicz.onion.ConvertersFactory"/><converter format="html"/><converter format="json"/><converter format="error" lenient="false"/><entity class="Foo" converters="json, error"><page response="404" dest="not-found"/><page response="503" dest="error"/></entity><entity class="Bar" converters="json, html, error"><page response="400" dest="bad-request"/><page response="500" dest="internal"/></entity><entity class="Buzz" converters="json, html"><page response="502" dest="bad-gateway"/></entity></b:beans>

仔细观察,仍然是该框架可以完全理解的Spring XML文件-您将学习如何实现。 您可以为每个顶级定制XML标记运行任意代码,例如,一次性出现<entity/>寄存器库,服务和控制器Bean定义。 要实现的第一件事是为我们的名称空间编写自定义XML模式。 这并不难,并且将允许IntelliJ IDEA以XML显示代码完成:

<?xml version="1.0" encoding="UTF-8"?>
<schemaxmlns:tns="http://nurkiewicz.blogspot.com/spring/onion/spring-onion.xsd"xmlns="http://www.w3.org/2001/XMLSchema"targetNamespace="http://nurkiewicz.blogspot.com/spring/onion/spring-onion.xsd"elementFormDefault="qualified"attributeFormDefault="unqualified"><element name="entity"><complexType><sequence><element name="page" type="tns:Page" minOccurs="0" maxOccurs="unbounded"/></sequence><attribute name="class" type="string" use="required"/><attribute name="converters" type="string"/></complexType></element><complexType name="Page"><attribute name="response" type="int" use="required"/><attribute name="dest" type="string" use="required"/></complexType><element name="converter"><complexType><attribute name="format" type="string" use="required"/><attribute name="lenient" type="boolean" default="true"/></complexType></element></schema>

模式完成后,我们必须使用两个文件在Spring中进行注册:

/META-INF/spring.schemas

http\://nurkiewicz.blogspot.com/spring/onion/spring-onion.xsd=/com/blogspot/nurkiewicz/onion/ns/spring-onion.xsd

/META-INF/spring.handlers

http\://nurkiewicz.blogspot.com/spring/onion/spring-onion.xsd=com.blogspot.nurkiewicz.onion.ns.OnionNamespaceHandler

一个将模式URL映射到本地的模式位置,另一个则指向所谓的名称空间处理程序。 此类非常简单–它告诉如何处理Spring配置文件中遇到的该命名空间中的每个顶级自定义XML标签:

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;public class OnionNamespaceHandler extends NamespaceHandlerSupport {public void init() {registerBeanDefinitionParser("entity", new EntityBeanDefinitionParser());registerBeanDefinitionParser("converter", new ConverterBeanDefinitionParser());}
}

因此,当Spring找到XML的<converter format="html"/>片段时,它知道需要使用我们的ConverterBeanDefinitionParser 。 请记住,如果我们的自定义标记具有子代(例如<entity/> ),则仅对顶级标记调用bean定义解析器。 如何解析和处理孩子取决于我们自己。 好的,因此假设单个<converter/>标签可以创建以下两个bean:

<bean id="htmlConverter" class="com.blogspot.nurkiewicz.onion.Converter" factory-bean="convertersFactory" factory-method="build"><constructor-arg value="html.xml"/><constructor-arg value="true"/><property name="reader" ref="htmlReader"/>
</bean>
<bean id="htmlReader" class="com.blogspot.nurkiewicz.onion.ReaderFactoryBean"><property name="format" value="html"/>
</bean>

bean定义解析器的职责是以编程方式注册XML定义的bean定义。 我不会详细介绍API,但是将其与上面的XML代码段进行比较,它们相互之间非常接近:

import org.w3c.dom.Element;public class ConverterBeanDefinitionParser extends AbstractBeanDefinitionParser {@Overrideprotected AbstractBeanDefinition parseInternal(Element converterElement, ParserContext parserContext) {final String format = converterElement.getAttribute("format");final String lenientStr = converterElement.getAttribute("lenient");final boolean lenient = lenientStr != null? Boolean.valueOf(lenientStr) : true;final BeanDefinitionRegistry registry = parserContext.getRegistry();final AbstractBeanDefinition converterBeanDef = converterBeanDef(format, lenient);registry.registerBeanDefinition(format + "Converter", converterBeanDef);final AbstractBeanDefinition readerBeanDef = readerBeanDef(format);registry.registerBeanDefinition(format + "Reader", readerBeanDef);return null;}private AbstractBeanDefinition readerBeanDef(String format) {return BeanDefinitionBuilder.rootBeanDefinition(ReaderFactoryBean.class).addPropertyValue("format", format).getBeanDefinition();}private AbstractBeanDefinition converterBeanDef(String format, boolean lenient) {AbstractBeanDefinition converterBeanDef = BeanDefinitionBuilder.rootBeanDefinition(Converter.class.getName()).addConstructorArgValue(format + ".xml").addConstructorArgValue(lenient).addPropertyReference("reader", format + "Reader").getBeanDefinition();converterBeanDef.setFactoryBeanName("convertersFactory");converterBeanDef.setFactoryMethodName("build");return converterBeanDef;}
}

您是否看到parseInternal()如何接收表示<converter/>标签的XML Element ,提取属性并注册bean定义? 由您决定在AbstractBeanDefinitionParser实现中定义多少个bean。 请记住,我们在这里几乎没有构建配置,还没有实例化。 一旦XML文件被完全解析并且所有bean定义解析器被触发,Spring将开始引导我们的应用程序。 要记住的一件事是最后返回null 。 API期望您返回单个bean定义。 但是,无需限制自己, null就可以了。

我们支持的第二个定制标记是<entity/> ,它一次注册三个bean。 这很相似,因此没那么有趣,请参阅EntityBeanDefinitionParser完整源代码 。 可以找到的一个重要的实现细节是ManagedList的用法。 文档模糊地提到了它,但是它非常有价值。 如果要定义一个知道其ID的要注入的bean列表,简单的List<String>是不够的,则必须明确告诉Spring您的意思是一个bean引用列表:

List<BeanMetadataElement> converterRefs = new ManagedList<>();
for (String converterName : converters) {converterRefs.add(new RuntimeBeanReference(converterName));
}
return BeanDefinitionBuilder.rootBeanDefinition("com.blogspot.nurkiewicz.FooService").addPropertyValue("converters", converterRefs).getBeanDefinition();

使用JAXB简化bean定义解析器

好的,因此,现在您应该熟悉自定义Spring命名空间以及它们如何为您提供帮助。 但是,它们要求您使用原始XML DOM API解析自定义标签,因此级别很低。 但是我的队友发现,既然我们已经有了XSD模式文件,为什么不使用JAXB来处理XML解析呢? 首先,我们要求Maven在构建过程中生成表示XML类型和元素的Java bean:

<build><plugins><plugin><groupId>org.jvnet.jaxb2.maven2</groupId><artifactId>maven-jaxb22-plugin</artifactId><version>0.8.3</version><executions><execution><id>xjc</id><goals><goal>generate</goal></goals></execution></executions><configuration><schemaDirectory>src/main/resources/com/blogspot/nurkiewicz/onion/ns</schemaDirectory><generatePackage>com.blogspot.nurkiewicz.onion.ns.xml</generatePackage></configuration></plugin></plugins>
</build>

/target/generated-sources/xjc您会发现几个Java文件。 我喜欢生成的JAXB模型具有一些通用前缀,例如Xml ,可以通过在spring-onion.xsd旁边放置自定义bindings.xjb文件轻松实现:

<bindings version="1.0"xmlns="http://java.sun.com/xml/ns/jaxb"xmlns:xs="http://www.w3.org/2001/XMLSchema"extensionBindingPrefixes="xjc"><bindings schemaLocation="spring-onion.xsd" node="/xs:schema"><schemaBindings><nameXmlTransform><typeName prefix="Xml"/><anonymousTypeName prefix="Xml"/><elementName prefix="Xml"/></nameXmlTransform></schemaBindings></bindings></bindings>

它如何改变我们的自定义bean定义解析器? 以前我们有这个:

final String clazz = entityElement.getAttribute("class");
//...
final NodeList pageNodes = entityElement.getElementsByTagNameNS(NS, "page");
for (int i = 0; i < pageNodes.getLength(); ++i) {  //...

现在我们简单地遍历Java bean:

final XmlEntity entity = JaxbHelper.unmarshal(entityElement);
final String clazz = entity.getClazz();
//...
for (XmlPage page : entity.getPage()) {  //...

JaxbHelper只是一个简单的工具,可从外部隐藏检查的异常和JAXB机制:

public class JaxbHelper {private static final Unmarshaller unmarshaller = create();private static Unmarshaller create() {try {return JAXBContext.newInstance("com.blogspot.nurkiewicz.onion.ns.xml").createUnmarshaller();} catch (JAXBException e) {throw Throwables.propagate(e);}}public static <T> T unmarshal(Element elem) {try {return (T) unmarshaller.unmarshal(elem);} catch (JAXBException e) {throw Throwables.propagate(e);}}}

几句话作为总结。 首先,我不鼓励您为每个实体自动生成存储库/服务/控制器Bean定义。 实际上,这是一个不好的做法,但是我们所有人都熟悉该领域,因此我认为这将是一个很好的例子。 其次,更重要的是,自定义XML名称空间是一个功能强大的工具,当所有其他东西(即抽象bean , 工厂bean和Java配置)失败时,应将其用作最后的手段。 通常,您会希望在Spring顶部构建的框架或工具中使用这种功能。 在这种情况下,请在GitHub上查看完整的源代码 。

参考: Java和社区博客上的JCG合作伙伴 Tomasz Nurkiewicz的JAXB使自定义Spring命名空间变得更加容易 。

翻译自: https://www.javacodegeeks.com/2014/03/custom-spring-namespaces-made-easier-with-jaxb.html

spring jaxb

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/343789.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【渝粤教育】电大中专新媒体营销实务 (6)作业 题库

1.在不同的时间段&#xff0c;新媒体有着不同的内涵。这是指新媒体的&#xff08; &#xff09;。 A.相对概念 B.发展概念 C.时间概念 错误 正确答案&#xff1a;左边查询 学生答案&#xff1a;A 2.互联网媒体是指第四媒体&#xff0c;即移动网络的无线增值服务。该说法&#x…

什么是8口poe交换机?8口poe交换机有哪些特点?

八口POE交换机&#xff08;POE31008P&#xff09;提供了从一个网络节点利用5类以太网线的电源和数据的传输。81端口快速以太网端口能用于10/100Mps的连接&#xff0c;其中8个端口可以提供工业标准的IEEE802.3af电源。先进的自感知算法只为标准PD终端设备供电&#xff0c;因而不…

【渝粤教育】电大中专电商运营实操 (19)作业 题库

1.目前菜鸟网络依赖大数据和云计算已实现了哪些功能&#xff08; &#xff09; A.智能分单 B.智能发货 C.自动化仓库 D.物流云加速 E.以上都正确 错误 正确答案&#xff1a;左边查询 学生答案&#xff1a;A 2.电子商务未来发展的三大关键因素是支付、物流和商品。 &#xff08;…

oracle查看表的命令,Oracle常用查看表结构命令

获取表&#xff1a; select table_name from user_tables; //当前用户的表 select table_name from all_tables; //所有用户的表 select table_name from dba_tables; //包括系统表 select table_name from dba_tables where owner用户名 user_tables&#xff1a; table_name,t…

如何为您的AWS账户设置多因素身份验证(MFA)

步骤1 &#xff1a; 转到AWS控制台并使用您的用户名密码登录。 第2步 &#xff1a; 转到服务-> IAM 第三步&#xff1a; 单击您的根帐户上的激活MFA 第四步 &#xff1a; 在步骤3中&#xff0c;点击屏幕上的管理MFA按钮。 步骤5&#xff1a; 单击分配MFA设备。选…

【渝粤教育】电大中专电子商务网站建设与维护 (27)作业 题库

1阿里巴巴是于1999年创立的&#xff08; &#xff09;的网上贸易市场平台。 A企业对企业 B企业对消费者 C企业对零售商 D零售商对消费者 错误 正确答案&#xff1a;左边查询 学生答案&#xff1a;B 2目前&#xff0c;阿里巴巴集团旗下主要交易市场不包括哪个&#xff08; &…

电视光端机常见故障问题介绍

一提到电视光端机&#xff0c;可能就会让人想起传输距离远、保密性强、抗干扰能力强、传输性能好、容量大等优点&#xff0c;当然也不会忘记价格高这个特点。但是&#xff0c;我们在使用电视光端机的过程中难免会出现各种各样的故障问题&#xff0c;接下来就由飞畅科技的小编来…

【渝粤教育】电大中专药剂学基础知识_1作业 题库

1.胶囊剂不检查的项目是&#xff08;&#xff09;。 A.装量差异 B.崩解时限 C.硬度 D.水分 E.外观 正确 正确答案&#xff1a;左边查询 学生答案&#xff1a;C 2.成裂片和顶裂的原因正确的是&#xff08;&#xff09;。 A.压力分布的不均匀 B.颗粒中细粉太多 C.颗粒过干 D.弹性…

电视光端机应用范围及故障维护问题介绍

随着国内通信网络的发展&#xff0c;发展势头强劲&#xff0c;电视光端机应用的监控范围也越来越广。目前&#xff0c;电视光端机应用最多的方面就是长距离视频和数据的传输。在高速公路、银行、电力、电信等的监控领域都要求对视频信号进行远程的传输&#xff0c;目前主要的解…

【渝粤教育】电大中专新媒体营销实务 (16)作业 题库

1&#xff08;&#xff09;对新媒体的定义为&#xff1a;“以数字信息技术为基础&#xff0c;以互动传播为特点&#xff0c;具有创新形态的媒体。” A华纳兄弟总裁施瓦茨威格 B联合国教科文组织 C新传媒产业联盟秘书长王斌 错误 正确答案&#xff1a;左边查询 学生答案&#xf…

php项目部署lnmp,如何在lnmp环境里,部署多个php项目?

我有2个php项目&#xff0c;想放在同一个lnmp环境里如果你说两个项目是通过两个不同的域名来访问的话&#xff0c;直接参考以下conf文件内容第一段&#xff1a;server {listen 80 ;server_name www.host1.cc; #监听的hostnameroot /var/www/www_host1_cc/; #第一个项目…

linux文件系统的管理方法,Linux学习笔记:2.文件系统的管理命令(2)

1.命令touch&#xff1a;功能&#xff1a;若之前对应文件不存在&#xff0c;创建一个新文件&#xff1b;若存在&#xff0c;则修改这个文件的最后修改期限。语法&#xff1a;touch [参数] [文件名]主要参数&#xff1a;-a&#xff1a;只更改存取时间-c&#xff1a;不建立任何文…

光端机2m是什么意思,光端机E1与2M有什么关系?

光端机就是将多个E1信号变成光信号的设备&#xff0c;光端机也叫光传输设备。光端机根据传输E1&#xff08;就是2M&#xff09;口数量的多少&#xff0c;价格也不同。一般最小的光端机可以传输4个E1目前最大的光端机可以传输4032个E1每个E1包括30个电话。那么&#xff0c;光端机…

【渝粤教育】电大中专职业健康与安全_1作业 题库

1根据系统安全工程的观点&#xff0c;危险是指系统中存在导致发生不期望后果的可能性超过了&#xff08; &#xff09; A极限 B人们的承受程度 C危险度 D安全系数 错误 正确答案&#xff1a;左边查询 学生答案&#xff1a;A 2对职工来说&#xff0c;安全是&#xff08;&#x…

【渝粤教育】电大中专药物化学基础 (2)_1作业 题库

1.非特异性结构药物的药效主要取决于药物的&#xff08;&#xff09;。 A.给药途径 B.理化性质 C.剂型 D.构效关系 E.化学结构 错误 正确答案&#xff1a;左边查询 学生答案&#xff1a;E 2.药物的亲脂性与生物活性的关系是&#xff08;&#xff09;。 A.降低亲脂性&#xff0c…

ida调试linux程序,MAC使用IDA PRO远程调试LINUX程序

1 背景在学习Linux系统上的一些漏洞知识的时候&#xff0c;往往需要进行“实地测试”&#xff0c;但是在Linux系统上进行调试并不太方便&#xff0c;因为LINUX自带的GDB调试工具真的不太人性化&#xff0c;即使有GDBTUI之类的“伪图形界面调试器”&#xff0c;也跟IDA PRO之类的…

RS485数据光端机产品特点及技术参数介绍

485光端机提供RS-232/485/422串口转光纤功能&#xff0c;实现光纤与RS-232/485/422串口的数据双向透明传输。由于光纤传输距离远&#xff08;多模2KM&#xff0c;单模可达20&#xff0c;40&#xff0c;60KM&#xff09;&#xff0c;抗干扰能力强&#xff0c;是连接远程终端单元…

java 方法注解_使用Java注解不正确的方法

java 方法注解几乎没有什么Deprecated没有适当的文档看到Deprecated方法更令人生气的了。 我感到失落。 我应该仍然使用该方法吗&#xff1f; 可能这不是开发人员的意图&#xff0c;这就是为什么他/她添加了弃用注释。 我应该使用其他东西吗&#xff1f; 所以…。 使用Depreca…

[渝粤教育] 西南科技大学 高速公路 在线考试复习资料

高速公路——在线考试复习资料 一、单选题 1.加州承载比简称()。 A. B.NBA C. D.RB 2.在天气良好、交通量小、路面干净的条件下,中等技术水平的驾驶员在道路受限制部分能够保持安全而舒适行驶的最大速度称为()。 A.最佳车速 B.设计车速 C.运行车速 D.实际车速 3.避免在凸型竖…

传输设备,光端机的应用及故障分析

光端机是光通信系统中的传输设备&#xff0c;主要是进行光电转换及传输功用。一般用于电信、电力、监控、工业控制、视频传输等功能&#xff0c;在各个行业有着广泛的应用。常说的光端机指的是用于监控系统用来传输视频、数据、以太网、音频等综合信息的光端机。主要分模拟光端…