spring 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 = {“名称”,“姓氏”,“位置”,“年龄”,“ 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发送到原始队列中的。 现在让我们看一下发送者逻辑:
PlayerDetailsSenderImpl.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;
@Autowired
private JmsTemplate jmsTemplate;
@Override
public 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);
@Autowired
private Convertable<PlayerDetails> playerDetailsConverter;
@Autowired
private List<Enrichable<PlayerDetails>> listOfEnrichers;
@Autowired
private MessageConverter messageConverter;
@Autowired
@Qualifier("destinationPlayerSender")
private Sender<PlayerDetails> sender;
@Override
public 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);
@Override
public void enrich(PlayerDetails inputObject) {
LOGGER.debug("Enriching player [{}] with club data", new Object[] { inputObject.getSurname() });
// Simulating accessing DB or some other service
try {
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();
}
@Override
public 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();
}
@Override
public 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);
@Autowired
private MessageConverter messageConverter;
@Override
public 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侦听器,发送者和消息转换器的方法。
翻译自: https://www.javacodegeeks.com/2013/04/spring-jms-message-automatic-conversion-jms-template.html
spring jms 消息