spring jms _ activemq

参考链接:

http://bsnyderblog.blogspot.com/2010/02/using-spring-jmstemplate-to-send-jms.html

http://bsnyderblog.blogspot.com/2010/02/using-spring-to-receive-jms-messages.html

RecentlyIstumbleduponanumberofplacesinthesomedocsandmailinglistswhereclaimsaremadethattheSpringJmsTemplateisfullofanti-patterns,ishorriblyinefficientandshouldn'tbeused.WellI'mheretodebunktheseerroneousclaimsbypointingoutaclassintheSpringFrameworkthatwasoverlookedentirely.

TheSpringJmsTemplateisaconvenienceclassforsendingandreceivingJMSmessagesinasynchronousmanner.TheJmsTemplatewasoriginallydesignedtobeusedwithaJ2EEcontainerwherethecontainerprovidesthenecessarypoolingoftheJMSresources(i.e.,connections,consumersandproducers).SuchrequirementscamefromtheEJBspec.ButwhendevelopersbeganusingtheJmsTemplateoutsideofJ2EEcontainers,andbecausesomeJMSprovidersdonotoffercaching/poolingofJMSresources,adifferentsolutionwasnecessary.EntertheSpringCachingConnectionFactory.

TheCachingConnectionFactoryismeanttowrapaJMSprovider'sconnectiontoprovidecachingofsessions,connectionsandproducersaswellasautomaticconnectionrecovery.Bydefault,itusesasinglesessiontocreatemanyconnectionsandthismodelworksverywellwithmostMOMs.Butifyouneedtoscalefurther,youcanalsospecifythenumberofsessionstocacheusingthesessionCacheSizeproperty.

BelowisasnippetfromaSpringappcontextthatdemonstratestheconfigurationfortheCachingConnectionFactory

01

...

02

03

<!--AconnectiontoActiveMQ-->

04

05

<beanid="amqConnectionFactory"

06

07

class="org.apache.activemq.ActiveMQConnectionFactory"

08

09

p:brokerURL='tcp://localhost:61616"/>

10

11

12

13

<!--AcachedconnectiontowraptheActiveMQconnection-->

14

15

<beanid="cachedConnectionFactory"

16

17

class="org.springframework.jms.connection.CachingConnectionFactory"

18

19

p:targetConnectionFactory-ref="amqConnectionFactory"

20

21

p:sessionCacheSize="10"/>

22

23

24

25

<!--AdestinationinActiveMQ-->

26

27

<beanid="destination"

28

29

class="org.apache.activemq.command.ActiveMQQueue">

30

31

<constructor-argvalue="FOO.TEST"/>

32

33

</bean>

34

35

36

37

<!--AJmsTemplateinstancethatusesthecachedconnectionanddestination-->

38

39

<beanid="producerTemplate"

40

41

class="org.springframework.jms.core.JmsTemplate"

42

43

p:connectionFactory-ref="cachedConnectionFactory"

44

45

p:defaultDestination-ref="destination"/>

46

47

...

Asyoucansee,theconfigurationfortheCachingConnectionFactoryalongwiththeJmsTemplateisquitesimple.Furthermore,thesetwoclassesarealsobothintheorg.springframework.jmspackagepathsothey'rebothincludedinthespring-jmsjarfilemakingtheiruseeveneasier.

TheonlythinglefttodoisutilizethejmsTemplatebeaninyourJavacodetoactuallysendamessage.Thisisshownbelow:

01

publicclassSimpleMessageProducer{

02

03

04

05

privatestaticfinalLoggerLOG=Logger.getLogger(SimpleMessageProducer.class);

06

07

08

09

@Autowired

10

11

protectedJmsTemplatejmsTemplate;

12

13

14

15

protectedintnumberOfMessages=100;

16

17

18

19

publicvoidsendMessages()throwsJMSException{

20

21

StringBuilderpayload=null;

22

23

24

25

for(inti=0;i<numberOfMessages;++i){

26

27

28

29

payload=newStringBuilder();

30

31

payload.append("Message[").append(i).append("]sentat:").append(newDate());

32

33

34

35

jmsTemplate.send(newMessageCreator(){

36

37

publicMessagecreateMessage(Sessionsession)throwsJMSException{

38

39

TextMessagemessage=session.createTextMessage(payload.toString());

40

41

message.setIntProperty("messageCount",i);

42

43

LOG.info("Sendingmessagenumber["+i+"]");

44

45

returnmessage;

46

47

}

48

49

});

50

51

}

52

53

}

54

55

}

TheSimpleMessageProducerclassabovedemonstratestheuseofSpringautowiringtoresolvetherelationshipbetweenthejmsTemplatepropertyandtheproducerTemplateintheappcontextfurtherabove.ThenananonymousMessageCreatorinstanceisusedtoactuallycreateamessageforthejmsTemplatetosend.

TheJmsTemplateandtheCachingConnectionFactoryarebothverywidelyusedinbusinessesofallsizesthroughouttheworld.CoupledwithoneoftheSpringmessagelistenercontainers,theyprovideanidealsolution.

I'llelaborateonmessageconsumptionusingtheSpringDefaultMessageListenerContainerandtheSimpleMessageListenerContainerinafutureblogpost.

HaveyoueverhadaneedtocreateyourownJMSconsumer?Orwillyouhavethisneedinthefuture?Ifyouansweredyestoeitheroneofthesequestions,thispostwillsimplifyyourlife.

Inthepreviouspost,IdiscussedUsingtheSpringJmsTemplatetoSendJMSMessages.Asafollow-on,inthispostIwilldemonstratehowtoreceivemessagesusingSpringJMS.AlthoughthepreviouslymentionedJmsTemplatecanreceivemessagessynchronously,hereIwillfocusonasynchronousmessagereceptionusingtheSpringmessagelistenercontainerarchitecture,specificallytheDefaultMessageListenerContainer.

TheDefaultMessageListenerContainer(DMLC)isanotherwonderfulconvenienceclassthatispartoftheSpringFramework'sJMSpackage.AsyoucanseeintheJavadoc,theDMLCisnotasingleclass,butawell-abstractedhierarchyforthepurposeofreceivingmessages.ThereasonforthisisthattheDMLCtakesitsinspirationfromMessageDrivenBeans(MDB).

MDBswereoriginallydefinedintheEJB2.0specasastateless,transactionawaremessagelistenerthatuseJMSresourcesprovidedbytheJavaEEcontainer.MDBscanalsobepooledbytheJavaEEcontainerinordertoscaleup.Inshort,MDBsweredesignedforasynchronousmessagereceptioninawaythattheJavaEEcontainercouldmanagethem.Althoughtheintentionwasgood,unfortunatelythedisadvantagesofMDBsarenumerousincluding:

MDBsarestaticintheirconfigurationandcreation(theycannotbecreateddynamically)

MDBscanonlylistentoasingledestination

MDBscanonlysendmessagesafterfirstreceivingamessage

MDBsrequireanEJBcontainer(andthereforetheJavaEEcontainer)

AlthoughtheSpringDMLCtookitsinspirationfromMDBs,itdidnotreplicatethesedisadvantages;quitetheopposite,infact.TheSpringDMLCiscommonlyusedtocreatewhathavebecomeknownasMessage-DrivenPOJOs(MDP).MDPsofferallofthesamefunctionalityasMDBsbutwithoutthedisadvantageslistedabove.TheSpringDMLCprovidesmanyfeaturesincluding:

VariouslevelsofcachingoftheJMSresources(connectionsandsessions)andJMSconsumersforincreasedperformance

Theabilitytodynamicallygrowandshrinkthenumberofconsumerstoconcurrentlyprocessmessagesbasedonload(seesetConcurrentConsumersandsetMaxConcurrentConsumers)foradditionalperformance

Automaticallyre-establishesconnectionsifthemessagebrokerbecomesunavailable

AsynchronousexecutionofamessagelistenerusingtheSpringTaskExecutor

SupportforlocalJMStransactionsaswellasanexternaltransactionmanageraroundmessagereceptionandlistenerexecution

Supportforvariousmessageacknowledgementmodes,eachprovidingdifferentsemantics

Forsomesituations,itisimportanttounderstandtheadditionalerrorhandlingandtheredeliverysemanticsthatareprovidedbytheDMLC.Formoreinformation,seetheAbstractMessageListenerContainerJavaDoc.

ThereasonIrecommendtheDMLC(oreventheSimpleMessageListenerContainer)isbecausewritingJMSconsumerscanbealotofwork.Indoingso,youmustmanuallyhandleandmangetheJMSresourcesandtheJMSconsumers,anyconcurrencythatisnecessaryandanyuseoftransactions.Ifyou'veeverdonesuchworkyouknowhowarduousanderrorproneitcanbe.CertainlyMDBsprovidesomeofthesefeaturesbutwithalltheirdisadvantages.BycreatingMDPsusingtheSpringDMLC,Ihaveseenuserssaveatremendousamountoftimeandincreasetheirproductivitysignificantly.ThisisbecausetheDMLCoffersmuchflexibility,robustness,ahighamountofconfigurabilityandithaswidespreaddeploymentinbusinessesallovertheworld(soithasbeenwidelytested).

ComparedtoMDBs,useoftheSpringDMLCisactuallysurprisinglysimple.TheeasiestwaytogetstartedistousinganXMLconfigurationastheSpringDMLCprovidesJMSnamespacesupport.BelowisaSpringapplicationcontextthatdemonstratestheconfigurationtousetheSpringDMLCwithApacheActiveMQ:

01

<?xmlversion="1.0"encoding="UTF-8"?>

02

<beansxmlns="http://www.springframework.org/schema/beans"

03

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

04

xmlns:jms="http://www.springframework.org/schema/jms"

05

xmlns:p="http://www.springframework.org/schema/p"

06

xsi:schemaLocation="

07

http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd

08

http://www.springframework.org/schema/jmshttp://www.springframework.org/schema/jms/spring-jms-3.0.xsd">

09

10

<!--AJMSconnectionfactoryforActiveMQ-->

11

<beanid="connectionFactory"class="org.apache.activemq.ActiveMQConnectionFactory"

12

p:brokerURL="tcp://foo.example.com:61616"/>

13

14

<!--APOJOthatimplementstheJMSmessagelistener-->

15

<beanid="simpleMessageListener"class="com.mycompany.SimpleMessageListener">

16

17

<!--TheSpringmessagelistenercontainerconfiguration-->

18

<jms:listener-container

19

container-type="default"

20

connection-factory="connectionFactory"

21

acknowledge="auto">

22

<jms:listenerdestination="TEST.FOO"ref="simpleMessageListener"method="onMessage"/>

23

</jms:listener-container>

24

</beans>

ForfolkswhoarealreadyfamiliarwiththeSpringFramework,theXMLaboveisquitestraightforward.ItdefinesaconnectionfactorybeanforActiveMQ,amessagelistenerbeanandtheSpringlistener-container.Noticethatthejms:listenercontainsthedestinationnameandnotthelistener-container.Thislevelofseparationisimportantbecauseitmeansthatthelistener-containerisnottiedtoanydestination,onlythejms:listeneris.Youcandefineasmanyjms:listenerelementsasisnecessaryforyourapplicationandthecontainerwillhandlethemall.

Belowisthemessagelistenerimplementation:

01

importjavax.jms.JMSException;

02

importjavax.jms.Message;

03

importjavax.jms.MessageListener;

04

importjavax.jms.TextMessage;

05

06

importorg.apache.log4j.Logger;

07

08

publicclassMyMessageListenerimplementsMessageListener{

09

10

privatestaticfinalLoggerLOG=Logger.getLogger(MyMessageListener.class);

11

12

publicvoidonMessage(Messagemessage){

13

try{

14

TextMessagemsg=(TextMessage)message;

15

LOG.info("Consumedmessage:"+msg.getText());

16

}catch(JMSExceptione){

17

//TODOAuto-generatedcatchblock

18

e.printStackTrace();

19

}

20

}

21

22

}

Themessagelistenerimplementationisdeliberatelysimpleasitsonlypurposeistodemonstratereceivingthemessageandloggingthepayloadofthemessage.Althoughthislistenerimplementsthejavax.jms.MessageListenerinterface,thereareatotalofthreeoptionsavailableforimplementingamessagelistenertobeusedwiththeSpringDMLC:

Thejavax.jms.MessageListener-Thisiswhatwasusedintheexampleabove.ItisastandardizedinterfacefromtheJMSspecbuthandlingthreadingisuptoyou.

TheSpringSessionAwareMessageListener-ThisisaSpring-specificinterfacetheprovidesaccesstotheJMSsessionobject.Thisisveryusefulforrequest-responsemessaging.Justbeawarethatyoumustdoyourownexceptionhandling(i.e.,overridethehandleListenerExceptionmethodsoexceptionsarenotlost).

TheSpringMessageListenerAdapter-ThisisaSpring-specificinterfacethatallowsfortype-specificmessagehandling.UseofthisinterfaceavoidsanyJMS-specificdependenciesinyourcode.

SonotonlyistheSpringmessagelistenercontainereasytouse,itisalsofullofoptionstoadapttomanyenvironments.AndI'veonlyfocusedontheDefaultMessageListenerContainerhere,IhavenottalkedabouttheSimpleMessageListenerContainer(SMLC)beyondasimplemention.AtahighlevelthedifferenceisthattheSMLCisstaticandprovidesnosupportfortransactions.

OneverybigadvantageoftheSpringmessagelistenercontaineristhatthistypeofXMLconfigcanbeusedinaJavaEEcontainer,inaservletcontainerorstandalone.ThissameSpringapplicationcontextwillruninWeblogic,JBoss,TomcatorinastandaloneSpringcontainer.Furthermore,theSpringDMLCalsoworkswithjustaboutanyJMScompliantmessagingmiddlewareavailable.JustdefineabeanfortheJMSconnectionfactoryforyourMOMandpossiblytweakafewpropertiesonthelistener-containerandyoucanbeginconsumingmessagesfromdifferentMOMs.

IshouldalsonotethattheXMLconfigurationiscertainlynotarequirementeither.YoucangostraightfortheunderlyingJavaclassesinyourowncodeifyouwish.I'veusedeachstyleinvarioussituations,buttobeginusingtheSpringDMLCintheshortestamountoftime,IfindtheSpringXMLapplicationcontextthefastest.