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.