日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

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

發(fā)布時間:2023/12/3 javascript 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring jaxb_自定义Spring命名空间使JAXB变得更容易 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

spring jaxb

首先,讓我大聲說一下: Spring不再是XML繁重的了 。 實(shí)際上,如今,您可以使用大量注釋, Java配置和Spring Boot來編寫幾乎沒有XML或根本沒有XML的Spring應(yīng)用程序。 認(rèn)真地停止談?wù)揝pring和XML,這已經(jīng)成為過去。

話雖這么說,您可能仍然出于以下幾個原因而使用XML:您受困于舊代碼庫,出于其他原因選擇了XML,或者將Spring用作某些框架/平臺的基礎(chǔ)。 最后一種情況實(shí)際上很常見,例如Mule ESB和ActiveMQ在下面使用Spring來連接它們的依賴項(xiàng)。 而且,Spring XML是他們配置框架的方式。 但是,使用純Spring <bean/>配置消息代理或企業(yè)服務(wù)總線會很麻煩且冗長。 幸運(yùn)的是,Spring支持編寫可嵌入標(biāo)準(zhǔn)Spring配置文件中的自定義名稱空間 。 這些自定義的XML代碼片段在運(yùn)行時進(jìn)行了預(yù)處理,并且可以以簡潔明快的外觀(在XML允許的范圍內(nèi))一次注冊許多bean定義。 從某種意義上說,自定義名稱空間就像在運(yùn)行時擴(kuò)展為多個bean定義的宏。

為了讓您了解我們的目標(biāo),請想象一個具有多個業(yè)務(wù)實(shí)體的標(biāo)準(zhǔn)“企業(yè)”應(yīng)用程序。 對于每個實(shí)體,我們定義三個幾乎相同的bean:存儲庫,服務(wù)和控制器。 它們始終以相似的方式進(jìn)行布線,只是細(xì)節(jié)有所不同。 首先,我們的Spring XML看起來像這樣(我正在粘貼帶有縮略圖的屏幕截圖,以免引起您的注意,它巨大且huge腫):

這是一個“分層”的體系結(jié)構(gòu),因此我們將稱為onion的自定義命名空間-因?yàn)檠笫[具有層次性 -并且因?yàn)橐赃@種方式設(shè)計的系統(tǒng)使我哭泣。 在本文結(jié)束時,您將學(xué)習(xí)如何將這堆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>

仔細(xì)觀察,仍然是該框架可以完全理解的Spring XML文件-您將學(xué)習(xí)如何實(shí)現(xiàn)。 您可以為每個頂級定制XML標(biāo)記運(yùn)行任意代碼,例如,一次性出現(xiàn)<entity/>寄存器庫,服務(wù)和控制器Bean定義。 要實(shí)現(xiàn)的第一件事是為我們的名稱空間編寫自定義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中進(jìn)行注冊:

/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標(biāo)簽:

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

因此,當(dāng)Spring找到XML的<converter format="html"/>片段時,它知道需要使用我們的ConverterBeanDefinitionParser 。 請記住,如果我們的自定義標(biāo)記具有子代(例如<entity/> ),則僅對頂級標(biāo)記調(diào)用bean定義解析器。 如何解析和處理孩子取決于我們自己。 好的,因此假設(shè)單個<converter/>標(biāo)簽可以創(chuàng)建以下兩個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定義解析器的職責(zé)是以編程方式注冊XML定義的bean定義。 我不會詳細(xì)介紹API,但是將其與上面的XML代碼段進(jìn)行比較,它們相互之間非常接近:

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/>標(biāo)簽的XML Element ,提取屬性并注冊bean定義? 由您決定在AbstractBeanDefinitionParser實(shí)現(xiàn)中定義多少個bean。 請記住,我們在這里幾乎沒有構(gòu)建配置,還沒有實(shí)例化。 一旦XML文件被完全解析并且所有bean定義解析器被觸發(fā),Spring將開始引導(dǎo)我們的應(yīng)用程序。 要記住的一件事是最后返回null 。 API期望您返回單個bean定義。 但是,無需限制自己, null就可以了。

我們支持的第二個定制標(biāo)記是<entity/> ,它一次注冊三個bean。 這很相似,因此沒那么有趣,請參閱EntityBeanDefinitionParser完整源代碼 。 可以找到的一個重要的實(shí)現(xiàn)細(xì)節(jié)是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定義解析器

好的,因此,現(xiàn)在您應(yīng)該熟悉自定義Spring命名空間以及它們?nèi)绾螢槟峁椭?但是,它們要求您使用原始XML DOM API解析自定義標(biāo)簽,因此級別很低。 但是我的隊(duì)友發(fā)現(xiàn),既然我們已經(jīng)有了XSD模式文件,為什么不使用JAXB來處理XML解析呢? 首先,我們要求Maven在構(gòu)建過程中生成表示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您會發(fā)現(xiàn)幾個Java文件。 我喜歡生成的JAXB模型具有一些通用前綴,例如Xml ,可以通過在spring-onion.xsd旁邊放置自定義bindings.xjb文件輕松實(shí)現(xiàn):

<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) { //...

現(xiàn)在我們簡單地遍歷Java bean:

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

JaxbHelper只是一個簡單的工具,可從外部隱藏檢查的異常和JAXB機(jī)制:

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);}}}

幾句話作為總結(jié)。 首先,我不鼓勵您為每個實(shí)體自動生成存儲庫/服務(wù)/控制器Bean定義。 實(shí)際上,這是一個不好的做法,但是我們所有人都熟悉該領(lǐng)域,因此我認(rèn)為這將是一個很好的例子。 其次,更重要的是,自定義XML名稱空間是一個功能強(qiáng)大的工具,當(dāng)所有其他東西(即抽象bean , 工廠bean和Java配置)失敗時,應(yīng)將其用作最后的手段。 通常,您會希望在Spring頂部構(gòu)建的框架或工具中使用這種功能。 在這種情況下,請?jiān)贕itHub上查看完整的源代碼 。

參考: Java和社區(qū)博客上的JCG合作伙伴 Tomasz Nurkiewicz的JAXB使自定義Spring命名空間變得更加容易 。

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

spring jaxb

總結(jié)

以上是生活随笔為你收集整理的spring jaxb_自定义Spring命名空间使JAXB变得更容易的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。