javascript
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 /文件夾)
該命令或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偵聽器,發送者和消息轉換器的方法。
翻譯自: https://www.javacodegeeks.com/2013/04/spring-jms-message-automatic-conversion-jms-template.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的Spring JMS,消息自动转换,JMS模板的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Lambda表达式在Java 8中的简单
- 下一篇: 农行债市宝如何赚钱?