Spring JMS,消息自动转换,JMS模板

在我的一个项目中,我应该创建一个消息路由器,就像所有路由器都应该从一个主题中提取JMS消息并将其放入另一个主题中一样。 该消息本身是JMS文本消息,实际上包含XML消息。 收到消息后,我还应该添加一些其他数据来丰富消息。

我们不允许使用Spring或JAXB或任何其他有用的库,因此我决定检查使用它们进行此操作的难易程度。 最初,我只想使用Spring和JAXB,但在下一篇文章中,我将尝试通过使用Apache Camel重复相同的场景(这就是为什么在包名称中会找到单词“ camel”的原因)。 由于ActiveMQ消息传递服务器,JMS通信得以实现。 无论如何
回到代码。 我使用maven来解决依赖关系,这些是在JMS和JAXB以及消息转换方面必不可少的依赖关系:

pom.xml

<dependency><groupId>org.springframework</groupId><artifactId>spring-jms</artifactId><version>3.1.1.RELEASE</version></dependency><dependency><groupId>com.sun.xml.bind</groupId><artifactId>jaxb-impl</artifactId><version>2.2.6</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-oxm</artifactId><version>3.1.1.RELEASE</version></dependency>

这就是我划分项目的方式(在下一篇文章中,包装的骆驼部分会更有意义)。

为了通过JAXB将消息转换为对象,我需要一个模式:

播放器

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="PlayerDetails"><xsd:complexType><xsd:sequence><xsd:element name="Name" type="xsd:string" /><xsd:element name="Surname" type="xsd:string" /><xsd:element name="Position" type="PositionType" /><xsd:element name="Age" type="xsd:int" /><xsd:element name="TeamName" type="xsd:string" /></xsd:sequence></xsd:complexType></xsd:element><xsd:simpleType name="PositionType"><xsd:restriction base="xsd:string"><xsd:enumeration value="GK" /><xsd:enumeration value="DEF" /><xsd:enumeration value="MID" /><xsd:enumeration value="ATT" /></xsd:restriction></xsd:simpleType></xsd:schema>

我必须下载JAXB二进制文件并执行以下命令来创建我的对象:

./xjc.sh -p pl.grzejszczak.marcin.camel.jaxb.generated ~/PATH/TO/THE/SCHEMA/FILE/Player.xsd

注意

使用maven可以实现相同的目的。 这种方法不在博客的存储库中,但请相信我-它确实有效

将依赖项添加到pom

<dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.1</version>
</dependency>

使用插件(注意需要指定架构文件,或者默认情况下在以下位置搜索
src / main / xsd /文件夹)

<build><pluginManagement><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.5.1</version></plugin></plugins></pluginManagement><plugins><plugin><groupId>org.codehaus.mojo</groupId><artifactId>jaxb2-maven-plugin</artifactId><version>1.5</version><executions><execution><id>xjc</id><goals><goal>xjc</goal></goals></execution></executions><configuration><packageName>pl.grzejszczak.marcin.camel.jaxb.generated</packageName></configuration></plugin></plugins></build>

该命令或Maven插件的结果示例如下:

PlayerDetails.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.6 
// See http://java.sun.com/xml/jaxb 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2012.11.05 at 09:23:22 PM CET 
//package pl.grzejszczak.marcin.camel.jaxb.generated;import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;/*** Java class for anonymous complex type.* * The following schema fragment specifies the expected content contained within this class.* * * <complexType>*   <complexContent>*     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">*       <sequence>*         <element name="Name" type="{http://www.w3.org/2001/XMLSchema}string"/>*         <element name="Surname" type="{http://www.w3.org/2001/XMLSchema}string"/>*         <element name="Position" type="{}PositionType"/>*         <element name="Age" type="{http://www.w3.org/2001/XMLSchema}int"/>*         <element name="TeamName" type="{http://www.w3.org/2001/XMLSchema}string"/>*       </sequence>*     </restriction>*   </complexContent>* </complexType>* 
* * */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {"name","surname","position","age","teamName"
})
@XmlRootElement(name = "PlayerDetails")
public class PlayerDetails {@XmlElement(name = "Name", required = true)protected String name;@XmlElement(name = "Surname", required = true)protected String surname;@XmlElement(name = "Position", required = true)protected PositionType position;@XmlElement(name = "Age")protected int age;@XmlElement(name = "TeamName", required = true)protected String teamName;/*** Gets the value of the name property.* * @return*     possible object is*     {@link String }*     */public String getName() {return name;}/*** Sets the value of the name property.* * @param value*     allowed object is*     {@link String }*     */public void setName(String value) {this.name = value;}/*** Gets the value of the surname property.* * @return*     possible object is*     {@link String }*     */public String getSurname() {return surname;}/*** Sets the value of the surname property.* * @param value*     allowed object is*     {@link String }*     */public void setSurname(String value) {this.surname = value;}/*** Gets the value of the position property.* * @return*     possible object is*     {@link PositionType }*     */public PositionType getPosition() {return position;}/*** Sets the value of the position property.* * @param value*     allowed object is*     {@link PositionType }*     */public void setPosition(PositionType value) {this.position = value;}/*** Gets the value of the age property.* */public int getAge() {return age;}/*** Sets the value of the age property.* */public void setAge(int value) {this.age = value;}/*** Gets the value of the teamName property.* * @return*     possible object is*     {@link String }*     */public String getTeamName() {return teamName;}/*** Sets the value of the teamName property.* * @param value*     allowed object is*     {@link String }*     */public void setTeamName(String value) {this.teamName = value;}}

@XmlRootElement(name =“ PlayerDetails”)表示此类将在XML文件中输出一个Root节点。 JavaDoc所说的@XmlAccessorType(XmlAccessType.FIELD)意味着“除非XmlTransient注释,否则JAXB绑定类中的每个非静态,非瞬态字段都将自动绑定到XML。” 换句话说,如果您有一个由XmlTransient注释注释的字段,它将不会被序列化。 然后我们有@XmlType(name =“”,propOrder = {“ name”,“ surname”,“ position”,“ age”,“ teamName”})作为JavaDoc的 将类或枚举类型映射为XML模式类型 。 换句话说,我们的类被映射到架构中的PlayerDetails元素。 最后,我们有@XmlElement(name =“ Name”,required = true)批注,它是XML节点(元素)到类中字段的映射。 这是我要发送,接收,丰富和路由的消息:

RobertLewandowski.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PlayerDetails><Name>Robert</Name><Surname>Lewandowski</Surname><Position>ATT</Position>
</PlayerDetails>

现在开始我的JMS配置-我已经配置了始发和目的地队列

jms.properties

jms.origin=Initial.Queue
jms.destination=Routed.Queue

这是我的Spring配置(我在配置中添加了解释这些组件来源的注释):

jmsApplicationContext.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:context="http://www.springframework.org/schema/context"xmlns:jms="http://www.springframework.org/schema/jms" xmlns:oxm="http://www.springframework.org/schema/oxm"xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd"><!-- Spring configuration based on annotations --><context:annotation-config /><!-- Show Spring where to search for the beans (in which packages) --><context:component-scan base-package="pl.grzejszczak.marcin.camel" /><!-- Show Spring where to search for the properties files --><context:property-placeholder location="classpath:/camel/jms.properties" /><!-- The ActiveMQ connection factory with specification of the server URL --><bean id="activeMQConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"><property name="brokerURL" value="tcp://localhost:61616" /></bean><!-- Spring's jms connection factory --><bean id="cachingConnectionFactory"class="org.springframework.jms.connection.CachingConnectionFactory"><property name="targetConnectionFactory" ref="activeMQConnectionFactory" /><property name="sessionCacheSize" value="10" /></bean><!-- The name of the queue from which we will take the messages --><bean id="origin" class="org.apache.activemq.command.ActiveMQQueue"><constructor-arg value="${jms.origin}" /></bean><!-- The name of the queue to which we will route the messages --><bean id="destination" class="org.apache.activemq.command.ActiveMQQueue"><constructor-arg value="${jms.destination}" /></bean><!-- Configuration of the JmsTemplate together with the connection factory and the message converter --><bean id="producerTemplate" class="org.springframework.jms.core.JmsTemplate"><property name="connectionFactory" ref="cachingConnectionFactory" /><property name="messageConverter" ref="oxmMessageConverter" /></bean><!-- Custom message sender sending messages to the initial queue --><bean id="originPlayerSender" class="pl.grzejszczak.marcin.camel.manual.jms.PlayerDetailsSenderImpl"><property name="destination" ref="origin" /></bean><!-- Custom message sender sending messages to the destination queue --><bean id="destinationPlayerSender" class="pl.grzejszczak.marcin.camel.manual.jms.PlayerDetailsSenderImpl"><property name="destination" ref="destination" /></bean><!-- Custom message listener - listens to the initial queue  --><bean id="originListenerImpl" class="pl.grzejszczak.marcin.camel.manual.jms.ListenerImpl"/><!-- Custom message listener - listens to the destination queue  --><bean id="destinationListenerImpl" class="pl.grzejszczak.marcin.camel.manual.jms.FinalListenerImpl"/><!-- Spring's jms message listener container - specified the connection factory, the queue to be listened to and the component that listens to the queue --><bean id="jmsOriginContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"><property name="connectionFactory" ref="cachingConnectionFactory" /><property name="destination" ref="origin" /><property name="messageListener" ref="originListenerImpl" /></bean><!-- Spring's jms message listener container - specified the connection factory, the queue to be listened to and the component that listens to the queue --><bean id="jmsDestinationContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"><property name="connectionFactory" ref="cachingConnectionFactory" /><property name="destination" ref="destination" /><property name="messageListener" ref="destinationListenerImpl" /></bean><!-- Message converter - automatically marshalls and unmarshalls messages using the provided marshaller / unmarshaller--><bean id="oxmMessageConverter" class="org.springframework.jms.support.converter.MarshallingMessageConverter"><property name="marshaller" ref="marshaller" /><property name="unmarshaller" ref="marshaller" /></bean><!-- Spring's JAXB implementation of marshaller - provided a class the JAXB generated class --><oxm:jaxb2-marshaller id="marshaller"><oxm:class-to-be-bound name="pl.grzejszczak.marcin.camel.jaxb.generated.PlayerDetails" /></oxm:jaxb2-marshaller></beans>

现在让我们看一下Java代码-让我们从具有主要功能的类开始

ActiveMQRouter.java

package pl.grzejszczak.marcin.camel.manual;import java.io.File;
import java.util.Scanner;import javax.jms.JMSException;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;import pl.grzejszczak.marcin.camel.jaxb.PlayerDetailsConverter;
import pl.grzejszczak.marcin.camel.jaxb.generated.PlayerDetails;
import pl.grzejszczak.marcin.camel.manual.jms.Sender;public class ActiveMQRouter {/*** @param args* @throws JMSException*/public static void main(String[] args) throws Exception {ApplicationContext context = new ClassPathXmlApplicationContext("/camel/jmsApplicationContext.xml");@SuppressWarnings("unchecked")Sender<PlayerDetails> sender = (Sender<PlayerDetails>) context.getBean("originPlayerSender");Resource resource = new ClassPathResource("/camel/RobertLewandowski.xml");Scanner scanner = new Scanner(new File(resource.getURI())).useDelimiter("\\Z");String contents = scanner.next();PlayerDetailsConverter converter = context.getBean(PlayerDetailsConverter.class);sender.sendMessage(converter.unmarshal(contents));}
}

我们可以在这里看到的是,我们从类路径初始化了Spring上下文,并检索了名为originPlayerSender的bean。 该组件用于将消息发送到初始队列。 为了发送消息,我们从类路径中检索文件RobertLewandowski.xml,并通过Scanner类将其读取为String变量。 接下来,我们使用自定义的PlayerDetailsConverter类将String内容解组到PlayerDetails对象中,该对象实际上由originPlayerSender发送到原始队列。 现在让我们看一下发送者逻辑:

PlayerDetailsS​​enderImpl.java

package pl.grzejszczak.marcin.camel.manual.jms;import javax.jms.Destination;
import javax.jms.JMSException;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;import pl.grzejszczak.marcin.camel.jaxb.generated.PlayerDetails;@Component
public class PlayerDetailsSenderImpl implements Sender<PlayerDetails> {private static final Logger LOGGER = LoggerFactory.getLogger(PlayerDetailsSenderImpl.class);private Destination destination;@Autowiredprivate JmsTemplate jmsTemplate;@Overridepublic void sendMessage(final PlayerDetails object) throws JMSException {LOGGER.debug("Sending [{}] to topic [{}]", new Object[] { object, destination });jmsTemplate.convertAndSend(destination, object);}public Destination getDestination() {return destination;}public void setDestination(Destination destination) {this.destination = destination;}}

此类正在实现我的Sender接口,该接口提供sendMessage函数。 我们正在使用JmsTemplate对象转换消息并将其发送到通过Spring注入的给定目标。 好的,现在我们已经发送了消息,有人必须检索它:

ListenerImpl.java

package pl.grzejszczak.marcin.camel.manual.jms;import java.util.List;import javax.jms.BytesMessage;
import javax.jms.Message;
import javax.jms.MessageListener;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.stereotype.Component;import pl.grzejszczak.marcin.camel.enricher.Enrichable;
import pl.grzejszczak.marcin.camel.jaxb.Convertable;
import pl.grzejszczak.marcin.camel.jaxb.generated.PlayerDetails;@Component
public class ListenerImpl implements MessageListener {private static final Logger LOG = LoggerFactory.getLogger(ListenerImpl.class);@Autowiredprivate Convertable<PlayerDetails> playerDetailsConverter;@Autowiredprivate List<Enrichable<PlayerDetails>> listOfEnrichers;@Autowiredprivate MessageConverter messageConverter;@Autowired@Qualifier("destinationPlayerSender")private Sender<PlayerDetails> sender;@Overridepublic void onMessage(Message message) {if (!(message instanceof BytesMessage)) {LOG.error("Wrong msg!");return;}PlayerDetails playerDetails = null;try {playerDetails = (PlayerDetails) messageConverter.fromMessage(message);LOG.debug("Enriching the input message");for (Enrichable<PlayerDetails> enrichable : listOfEnrichers) {enrichable.enrich(playerDetails);}LOG.debug("Enriched text message: [{}]", new Object[] { playerDetailsConverter.marshal(playerDetails) });sender.sendMessage(playerDetails);} catch (Exception e) {LOG.error("Exception occured", e);}}}

此类包含实现Enrichable接口的所有类的列表,借助该类,它可以提供消息的丰富内容,而无需知道系统中丰富程序的数量。 还有一个PlayerDetailsConverter类,可帮助编组和解组PlayerDetails。 丰富了消息后,它将通过实现Sender接口并具有destinationPlayerSender ID的Bean将其发送到目标队列。 重要的是要记住,我们从队列中收到的是BytesMessage,因此这就是我们进行初始检查的原因。 让我们看一下其中一个扩展程序(另一个是在PlayerDetails对象中设置另一个字段)

ClubEnricher.java

package pl.grzejszczak.marcin.camel.enricher;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import pl.grzejszczak.marcin.camel.jaxb.generated.PlayerDetails;@Component("ClubEnricher")
public class ClubEnricher implements Enrichable<PlayerDetails> {private static final Logger LOGGER = LoggerFactory.getLogger(ClubEnricher.class);@Overridepublic void enrich(PlayerDetails inputObject) {LOGGER.debug("Enriching player [{}] with club data", new Object[] { inputObject.getSurname() });// Simulating accessing DB or some other servicetry {Thread.sleep(2000);} catch (InterruptedException e) {LOGGER.error("Exception while sleeping occured", e);}inputObject.setTeamName("Borussia Dortmund");}}

如您所见,该类只是在模拟对数据库或任何其他服务的访问,然后在输入的PlayerDetails对象中设置团队名称。 现在让我们看一下转换机制:

PlayerDetailsConverter.java

package pl.grzejszczak.marcin.camel.jaxb;import java.io.ByteArrayOutputStream;
import java.io.OutputStream;import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;import org.apache.activemq.util.ByteArrayInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import pl.grzejszczak.marcin.camel.jaxb.generated.PlayerDetails;@Component("PlayerDetailsConverter")
public class PlayerDetailsConverter implements Convertable<PlayerDetails> {private static final Logger LOGGER = LoggerFactory.getLogger(PlayerDetailsConverter.class);private final JAXBContext jaxbContext;private final Marshaller jaxbMarshaller;private final Unmarshaller jaxbUnmarshaller;public PlayerDetailsConverter() throws JAXBException {jaxbContext = JAXBContext.newInstance(PlayerDetails.class);jaxbMarshaller = jaxbContext.createMarshaller();jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);jaxbUnmarshaller = jaxbContext.createUnmarshaller();}@Overridepublic String marshal(PlayerDetails object) {OutputStream stream = new ByteArrayOutputStream();try {jaxbMarshaller.marshal(object, stream);} catch (JAXBException e) {LOGGER.error("Exception occured while marshalling", e);}return stream.toString();}@Overridepublic PlayerDetails unmarshal(String objectAsString) {try {return (PlayerDetails) jaxbUnmarshaller.unmarshal(new ByteArrayInputStream(objectAsString.getBytes()));} catch (JAXBException e) {LOGGER.error("Exception occured while marshalling", e);}return null;}}

在构造函数中,我们设置了一些JAXB组件-JAXBContext,JAXB Marshaller和JAXB Unmarshaller,它们具有必要的封送和取消封送方法。 最后但并非最不重要的是FinalListenerImpl,它正在侦听来自目标队列的入站消息并关闭应用程序。

FinalListenerImpl.java

package pl.grzejszczak.marcin.camel.manual.jms;import javax.jms.BytesMessage;
import javax.jms.Message;
import javax.jms.MessageListener;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.stereotype.Component;import pl.grzejszczak.marcin.camel.jaxb.generated.PlayerDetails;@Component
public class FinalListenerImpl implements MessageListener {private static final Logger LOG = LoggerFactory.getLogger(FinalListenerImpl.class);@Autowiredprivate MessageConverter messageConverter;@Overridepublic void onMessage(Message message) {if (!(message instanceof BytesMessage)) {LOG.error("Wrong msg!");return;}PlayerDetails playerDetails = null;try {playerDetails = (PlayerDetails) messageConverter.fromMessage(message);if (playerDetails.getTeamName() != null) {LOG.debug("Message already enriched! Shutting down the system");System.exit(0);} else {LOG.debug("The message should have been enriched but wasn't");System.exit(1);}} catch (Exception e) {LOG.error("Exception occured", e);}}}

通过使用MessageConverter,在确认消息的类型正确之后,我们检查团队名称是否已填写-如果是这种情况,我们将终止应用程序。

日志如下:

2012-11-05 [main] org.springframework.context.support.ClassPathXmlApplicationContext:495 Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@34fbb7cb: startup date [Mon Nov 05 21:47:00 CET 2012]; root of context hierarchy
2012-11-05 [main] org.springframework.beans.factory.xml.XmlBeanDefinitionReader:315 Loading XML bean definitions from class path resource [camel/jmsApplicationContext.xml]
2012-11-05 [main] org.springframework.beans.factory.config.PropertyPlaceholderConfigurer:177 Loading properties file from class path resource [camel/jms.properties]
2012-11-05 [main] org.springframework.beans.factory.support.DefaultListableBeanFactory:557 Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3313beb5: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalRequiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.annotation.internalPersistenceAnnotationProcessor, myRoute,AgeEnricher, ClubEnricher, PlayerDetailsConverter, finalListenerImpl, listenerImpl, playerDetailsSenderImpl, org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0, activeMQConnectionFactory, cachingConnectionFactory, origin, destination, producerTemplate, originPlayerSender, destinationPlayerSender, originListenerImpl, destinationListenerImpl, jmsOriginContainer, jmsDestinationContainer, oxmMessageConverter, marshaller, org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy
2012-11-05 [main] org.springframework.oxm.jaxb.Jaxb2Marshaller:436 Creating JAXBContext with classes to be bound [class pl.grzejszczak.marcin.camel.jaxb.generated.PlayerDetails]
2012-11-05 [main] org.springframework.context.support.DefaultLifecycleProcessor:334 Starting beans in phase 2147483647
2012-11-05 [main] org.springframework.jms.connection.CachingConnectionFactory:291 Established shared JMS Connection: ActiveMQConnection {id=ID:marcin-SR700-38535-1352148424687-1:1,clientId=null,started=false}
2012-11-05 [main] pl.grzejszczak.marcin.camel.manual.jms.PlayerDetailsSenderImpl:26 Sending  to topic [queue://Initial.Queue]
2012-11-05 [jmsOriginContainer-1] pl.grzejszczak.marcin.camel.manual.jms.ListenerImpl:49 Enriching the input message
2012-11-05 [jmsOriginContainer-1] pl.grzejszczak.marcin.camel.enricher.AgeEnricher:17 Enriching player [Lewandowski] with age data
2012-11-05 [jmsOriginContainer-1] pl.grzejszczak.marcin.camel.enricher.ClubEnricher:16 Enriching player [Lewandowski] with club data
2012-11-05 [jmsOriginContainer-1] pl.grzejszczak.marcin.camel.manual.jms.ListenerImpl:53 Enriched text message: [<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PlayerDetails><Name>Robert</Name><Surname>Lewandowski</Surname><Position>ATT</Position><Age>19</Age><TeamName>Borussia Dortmund</TeamName>
</PlayerDetails>
]
2012-11-05 [jmsOriginContainer-1] pl.grzejszczak.marcin.camel.manual.jms.PlayerDetailsSenderImpl:26 Sending  to topic [queue://Routed.Queue]
2012-11-05 [jmsDestinationContainer-1] pl.grzejszczak.marcin.camel.manual.jms.FinalListenerImpl:35 Message already enriched! Shutting down the system

这就是通过Spring JMS模块和JAXB库,您可以轻松地为XML消息创建JMS侦听器,发送者和消息转换器的方法。

参考: Spring JMS,消息自动转换,来自我们的JCG合作伙伴 Marcin Grzejszczak的JMS模板 ,位于Blog上,用于编码上瘾者博客。

翻译自: https://www.javacodegeeks.com/2013/04/spring-jms-message-automatic-conversion-jms-template.html

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

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

相关文章

前端人英语学习的那点事儿

小时候英语学得不好&#xff0c;这个不能怪老师。后来自己想&#xff1a;反正以后我也不出国&#xff0c;加之学习方法不对&#xff0c;英语水平比较差劲、工作之后才发现&#xff0c;英语真是重要、第一手资料几乎都是英文的&#xff0c;很多前端书籍翻译得都挺那啥的&#xf…

大学物理质点动力学思维导图_生理学 | 思维导图

1.声明&#xff1a;第一部分的思维导图来源于网络&#xff0c;但是早就被传疯了。还是一句话&#xff0c;侵删。2.后面明显高清的思维导图是我自己画的,有版权.已经在公众号(id : 医学猿MIT)上传。下面来源&#xff1a;网络▲物质的跨膜转运▲肌细胞的收缩▲血液▲一级消除动力…

WB8使用说明-基础(引用)

1、静态引用链接&#xff1a; 通过设置如下属性来来静态引用CSS和JScssLinks : Array需要在页面中引用的css链接列表。该属性仅在首页或在iframe中运行的模块内有效&#xff0c;内置模块页面引用css请使用Wb.addLink方法。 jsLinks : Array需要在页面中引用的js链接列表。该属性…

jQuary总结11:jQuery插件封装---jQuery封装 手风琴 动画插件

完整代码下载点击我的GitHub: https://github.com/XingJYGo/jquery-accordion 1 手风琴的效果展示如下: 2 封装插件目录结构如下: 主要包括:HTML结构, CCS样式,JS文件以及jquary库. 3 插件封装步骤如下: 3-1首先,编写HTML静态结构: <div id"box"><ul><…

Spring MVC:表单处理卷。 2 –复选框处理

很难想象现代Web应用程序中没有表单复选框的情况。 在之前的一篇文章中&#xff0c;我写了有关Spring MVC中的表单处理的文章 &#xff0c;作为本系列文章的续篇&#xff0c;我将写有关Spring MVC表单的文章&#xff0c;尤其是关于复选框处理的文章 。 这篇文章将介绍标签的标准…

给你的博客换个装-园子换装指南

博客园有很多漂亮的皮肤&#xff0c;但总是有一些地方我不大喜欢&#xff0c;所以经过慎重考虑&#xff0c;我决定亲自动手换个装。本文将介绍博客园换装的一些基础&#xff08;不涉及标准皮肤的做法&#xff09;&#xff0c;如果你想让你的博客更炫&#xff0c;可以参考本文入…

表格过滤器_气缸选型其实并不复杂,知道这些再也不怕选错气缸(附计算表格)...

文/第e机械气动系统概述在介绍气缸之前我们先了解一下气动系统。气动控制技术在国民经济各个领域&#xff0c;最近这些年, 它与传感器技术、电子信息技术密切融合&#xff0c;发展成为包括控制、传动和检测等在内的自动化技术, 现在已发展成为自动化领域的重要组成部分。气动控…

java中equals()和==的区别

java中的数据类型 基础数据类型 基础数据类型有byte、short、char、int、long、float、double、bool、String。除了 String 会比较地址,其它的基础类型的比较,使用 和 equals() 两者都是比较值。 String类的equals()方法源码 1 public boolean equals(Object anObject) {2 …

乒乓球比赛赛程_10月5日至10月11日中央电视台直播录播乒乓球比赛安排

10月5日至10月11日这一周中央电视台居然没有播乒乓球比赛?全国乒乓球锦标赛从5日开始进行各单项比赛&#xff0c;7日进行混双决赛&#xff0c;9日进行男双决赛和女单决赛&#xff0c;10日进行女双决赛和男单决赛。场场都是精彩好看的比赛&#xff0c;中央电视台体育频道一场都…

集合实例(集合覆盖)

集合覆盖是一种优化求解问题&#xff0c;对很多组合数学和资源选择问题给出了很好的抽象模型。 问题如下&#xff1a;给定一个集合S&#xff0c;集合P由集合S的子集A1到An组成&#xff0c;集合C由集合P中的一个或多个子集组成。如果S中的每个成员都包含在C的至少一个子集中则称…

关闭运动轨迹_网球初学者如何正确入门网球运动,有哪些学习细节

网球是一个非常有趣的球类运动。 当您开始入门时&#xff0c;您会越来越喜欢它。 那么网球初学者应该如何正确入门呢&#xff1f; 有什么独特的入门经验&#xff1f;即使没有网球经验&#xff0c;只要您能正确正确地进行定期训练&#xff0c;仍然可以取得很大的进步。首先&…

phpstorm+wamp+xdebug配置php调试环境

本篇文章主要是&#xff1a;教大家如果搭建一套phpstormwampxdebug调试php的环境现在大多数的程序员使用的调试方式一般都是echo, var_dump, file_put_contents等其他方式&#xff0c;效率比较低下&#xff0c;因此我们有必要学习用工具调试&#xff0c;工具调试主要可以用来解…

计算机专用英语1500词带音标,带音标的计算机英语1500词

带音标的计算机英语1500词 (46页)本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01;29.9 积分&#xfeff;计算机专用英语词汇1500词《电脑专业英语》1. file [fail] n. 文件&#xff1b;v. 保存文件 2. …

需求改进与系统设计

第一部分 需求与原型改进 1.1改进的原型 1.1.1 改进说明 相较上一次的原型&#xff0c;这一次我们确定了主题颜色&#xff0c;并且使功能一眼就能看懂&#xff0c;让新用户能很快上手。 并且进一步完善了前期的调查问卷分析。得出结论同学们不去食堂吃饭的大部分原因是排队…

了解ADF Faces clientComponent属性

我相信大多数ADF开发人员都知道ADF Faces属性clientComponent 。 在这篇文章中&#xff0c;我将展示此属性实际上如何影响组件渲染以及它如何改变其行为。 让我们开始考虑一个非常简单的示例&#xff1a; <af:inputText label"Label 1" id"it1" /> …

谈谈一些有趣的CSS题目(十五)-- 谈谈 CSS 关键字 initial、inherit 和 unset

开本系列&#xff0c;谈谈一些有趣的 CSS 题目&#xff0c;题目类型天马行空&#xff0c;想到什么说什么&#xff0c;不仅为了拓宽一下解决问题的思路&#xff0c;更涉及一些容易忽视的 CSS 细节。解题不考虑兼容性&#xff0c;题目天马行空&#xff0c;想到什么说什么&#x…

小程序沉浸式_企业开发小程序:客户裂变式增长

最近几年&#xff0c;各行各业中都有不少企业、商家获客难窘境。因此&#xff0c;很多企业、商家想知道&#xff1a;"怎么做&#xff0c;才能获取到大量流量&#xff1f;"小编给大家推荐一种方式&#xff1a;开发一个微信小程序&#xff0c;然后利用小程序来获取大量…

[CSS] Scale on Hover with Transition

效果 源码 <!doctype html><html class"outline color"><head><meta charset"utf-8"><title>图片scale动画</title><style>.img-box {position: relative;width: 740px;height: 420px;overflow: hidden;}/* 彩色…

热敏电阻温度特性曲线_热敏电阻与体温计的应用关系

相信体温计大家都熟悉&#xff0c;热敏电阻与体温计的应用关系大家都知道吗&#xff1f;热敏电阻热敏电阻探头测量体温的原理又是什么呢&#xff0c;小编跟大家分析一下&#xff0c;希望以下详细的介绍能帮助到大家&#xff01;热敏电阻探头测量体温的原理分析如下&#xff1a;…

1.Strategy Pattern(策略模式)

策略模式&#xff08;Strategy Pattern&#xff09;&#xff1a; 我的理解&#xff0c;将代码中每个变化之处抽出&#xff0c;提炼成一个一个的接口或者抽象类&#xff0c;让这些变化实现接口或继承抽象类成为具体的变化类。再利用多态的功能&#xff0c;可将变化之处用接口或抽…