1 Introduction
   Java Management Extension (JMX) API定义于JSR
3åQŒç”¨äºŽåº”用程åºç®¡ç†ã€‚这些API对于被管ç†çš„应用½E‹åºæ¥è¯´æ˜¯æœ¬åœ°çš„。也ž®±æ˜¯è¯ß_¼Œåœ¨JSR
160å‘布之å‰åQŒå¦‚果客æˆïL«¯è¦é€šè¿‡JMXæ¥ç®¡ç†å’Œç›‘控˜qœç¨‹çš„应用程åºï¼Œòq¶æ²¡æœ‰æ ‡å‡†çš„åšæ³•。JSR 160扩展了JSR
3åQŒæä¾›äº†æ ‡å‡†çš„API用于˜qžæŽ¥åˆ°æ”¯æŒJMX的远½E‹åº”用程åºã€‚JSR 255ž®†ä¼šæŠŠJMXå‡çñ”åˆ?.0åQŒåƈå¯èƒ½ä½“现在Java 7ä¸ã€?br />   目å‰JSR 160定义了基于RMIåQˆæ”¯æŒRMI/JRMP å’?RMI/IIOPåQ‰çš„˜qžæŽ¥å™¨ï¼Œ˜q˜å®šä¹‰äº†å¯é€‰çš„JMXMP˜qžæŽ¥å™¨ï¼Œå®ƒåŸºäºŽTCP Socketå’ŒJavaåºåˆ—化机制ã€?/p>
Â
2 JMX Remoting API
2.1 JMXServiceURL
   JMXServiceURLç”¨äºŽæ ‡è¯†JMXConnectorServeråQŒå®ƒæ˜¯é‡‡ç”¨ä»¥ä¸‹åÅžå¼çš„å—符ä¸ÔŒ¼š
   service:jmx:<protocol>://[[[ <host>]: <port>]/ <path>]
  Â
"protocol" 指定了å议,例如åQšrmiã€iiopã€jmxmp 或è€?soapã€?host"ã€?port" å’?
"path"是å¯é€‰çš„。JMXServiceURLòq¶ä¸‘³ä»¥æè¿°æ‰€æœ‰çš„用于˜qžæŽ¥åˆ°JMXConnectorServer的酾|®ä¿¡æ¯ï¼ˆä¾‹å¦‚é…ç½®
RMIClientSocketFactory å’ŒRMIServerSocketFactoryåQ‰ï¼Œå› æ¤åœ¨æž„é€ JMXConnectorServer å’?
JMXConnector的时候,˜q˜å¯èƒ½éœ€è¦é€šè¿‡ä¸€ä¸ªMap实例指定其它属性ã€?/p>
Â
2.2 JMXConnectorServer
   JMXConnectorServer
是MBeanServer端的¾l„äšgåQŒå®ƒéœ€è¦è¢«å…Œ™”到MBeanServeråQšå¯ä»¥é€šè¿‡åœ¨åˆ›å»ºJMXConnectorServerçš„æ—¶å€™æ˜¾å¼æŒ‡å®?
MBeanServeråQ›ä¹Ÿå¯ä»¥æŠŠJMXConnectorServeråQˆæœ¬íw«æ˜¯ä¸€ä¸ªMBeanåQ‰æ³¨å†Œåˆ°MBeanServerä¸ã€?br />  Â
在被兌™”到MBeanServer之åŽåQŒéœ€è¦å¯åЍJMXConnectorServer以处ç†å®¢æˆïL«¯çš„è¯·æ±‚ã€‚åŒæ øP¼Œå¦‚æžœå¸Œæœ›åœæ¢å¤„ç†å®¢æˆ·ç«¯çš„è¯äh±‚åQŒé‚£ä¹ˆéœ€
è¦åœæ¢JMXConnectorServer。JMXConnectorServerè¢«åœæ¢ä¹‹åŽï¼Œä¸åº”该试å›ùN‡æ–°å¯åŠ¨å®ƒåQŒè€Œæ˜¯åº”该ž®†å…¶ä¸¢å¼ƒã€?br />   最好通过JMXConnectorServerFactoryæ¥åˆ›å»ºJMXConnectorServeråQŒä¾‹å¦‚:
   在以上的例åä¸ï¼Œåˆ›å¾JMXConnectorServer的时候指定了MBeanServer。以下是一个将JMXConnectorServerä½œäØ“MBean注册到MBeanServer的例å:
Â Â Â éœ€è¦æ³¨æ„的是,在这个例åä¸ä½¿ç”¨äº†ä¸‰¿Uä¸åŒçš„æ–¹å¼å¯åЍJMXConnectorServeråQšç¬¬ä¸€¿Uæ–¹å¼æ˜¯ç›´æŽ¥è°ƒç”¨cntorServer对象çš? startæ–ÒŽ³•åQ›ç¬¬äºŒç§æ–¹å¼æ˜¯é€šè¿‡MBeanServer调用MBean的方法;½W¬ä¸‰¿Uæ–¹å¼æ˜¯ä½¿ç”¨äº? MBeanServerInvocationHandleråQŒå®ƒ¾l§æ‰¿è‡ªInvocationHandleråQŒç”¨äºŽä»ŽMBeançš„ç®¡ç†æŽ¥å£å‘ MBeanServerä¸çš„ MBean è½¬å‘æ–ÒŽ³•调用。当调用从newProxyInstance()æ–ÒŽ³•˜q”回的代ç†å¯¹è±¡ä¸Šçš„toString()ã€hashCode() å’Œequals(Object)½{‰æ–¹æ³•æ—¶åQŒè¿™äº›æ–¹æ³•è°ƒç”¨åŒæ ·ä¹Ÿä¼šè¢«è½¬å‘到MBeanServerä¸çš„MBean åQŒå› æ¤å½“且仅å½?MBean 在其½Ž¡ç†æŽ¥å£ä¸å£°æ˜Žäº†˜q™äº›æ–ÒŽ³•æ—¶æ‰èƒ½å¦‚æ¤æ“作,å¦åˆ™ä¼šæŠ›å‡ºå¼‚常ã€?/p>
Â
2.3 JMXConnector
 Â
JMXConnector是客æˆïL«¯çš„组ä»Óž¼Œå®¢æˆ·ç«¯ç¨‹åºé€šè¿‡å®ƒè¿žæŽ¥åˆ°˜qœç¨‹çš„MBeanServer。客æˆïL«¯å¯ä»¥é€šè¿‡JMXConnector获得˜qœç¨‹
MBeanServer的MBeanServerConnection
接å£åQŒåƈ以类似本地的方å¼ä½¿ç”¨å®ƒã€‚JMXConnector˜q˜æ”¯æŒåœ¨˜qœç¨‹çš„MBeanServer上注册本地或者远½E‹çš„通知监å¬å™¨ï¼Œä»¥æŽ¥æ”¶æ¥è‡ªè¿œ½E?
MBeanServer的通知ã€?br />   最好通过JMXConnectorFactoryæ¥åˆ›å»ºJMXConnectoråQŒä¾‹å¦‚:
  Â
éœ€è¦æ³¨æ„的是,以上的例åä¸é‡‡ç”¨äº†ä¸¤ä¸ªä¸åŒçš„Map对象ä¿å˜ç›¸å…³çš„属性:一个用于实例化åQ›å¦å¤–一个用于连接。MBeanServerConnection
接å£åœ¨JMX 1.2ä¸å®šä¹‰ï¼Œç”¨äºŽæ”¯æŒremote
API。由于之å‰ç‰ˆæœ¬çš„MBeanServer接å£ä¸èƒ½ç›´æŽ¥è¢«å®¢æˆïL«¯ä½¿ç”¨åQˆä¾‹å¦‚å…¶registerMBean(), deserialize(),
getClassLoader()½{‰æ–¹æ³•对于客æˆïL«¯æ¥è¯´æ²¡æœ‰æ„义åQ‰ï¼Œå› æ¤åœ¨JMX
1.2ä¸ï¼ŒMBeanServer接壾l§æ‰¿è‡ªMBeanServerConnection接å£ã€?br />
  Â
RMIConnectoræ˜¯æ ‡å‡†çš„JMXConnector。由于它使用RMIåè®®åQŒå› æ¤éœ€è¦ä¸€ä¸ªstub
objectæ¥å¤„ç†RMI调用的细节。stub class通常å˜åœ¨äºŽå®¢æˆïL«¯çš„类路径上,但是stub
objecté€šå¸¸æ˜¯ä»Žå‘½åæœåŠ¡å™¨å¤„ä¸‹è²åQŒå› æ¤RMI客户端需è¦çŸ¥é“stub object被绑定到RMI server上的路径。JSR
160定义了两¿U获得stub object的方å¼ï¼š
   ½W¬ä¸€¿Uæ–¹å¼ä¸éœ€è¦å‘½åæœåС噍åQŒè€Œæ˜¯ž®†stub
object¾~–ç 为JMXServiceURL的一部分åQŒå³"encoded form"。如果采用RMI/JRMPåè®®åQŒé‚£ä¹ˆå¯¹stub
object被åºåˆ—化之åŽçš„æ‰€æœ‰å—节进行Base64¾~–ç åQŒç„¶åŽå°†¾~–ç åŽçš„å—符æ·ÕdŠ åˆ°JMXServiceURLä¸ï¼Œòq¶ä¸”ä»?stub/开始;如果采用
RMI/ IIOPåQŒé‚£ä¹ˆIORè¢«æ·»åŠ åˆ°JMXServiceURLä¸ï¼Œòq¶ä»¥/ior/开始。以下是个例å:
   ½W¬äºŒ¿Uæ–¹å¼æ˜¯åœ¨JMXServiceURL䏿Œ‡å®šå‘½åæœåŠ¡å™¨å’Œstub object被绑定到的JNDI路径åQŒå³"JNDI form"。在JMXServiceURLä¸ä»¥/jndi/开始。将JNDI的相关酾|®ä¼ 递给RMIConnectorçš„æ–¹å¼æœ‰å¤šç§ã€‚例如URL 'rmi://namingHost:1099/jndiPath'æŒ‡æ˜Žå‘½åæœåŠ¡å™¨åœ¨å䨓'namingHost'的主æœÞZ¸Šòq¶ç›‘å?099端å£åQŒå‘½åæœåŠ? 器是rmiregistryåQŒèµ\径是'/jndiPath'ã€‚åŒæ ·URL 'iiop://namingHost:900/jndiPath'æŒ‡æ˜Žå‘½åæœåŠ¡å™¨åœ¨å䨓'namingHost'的主æœÞZ¸Šòq¶ç›‘å?00端å£åQŒå‘½åæœåС噍 是COSå‘½åæœåŠ¡åQŒèµ\径是'/jndiPath'。以下是个例å:
   æ¤å¤–åQŒJNDI属性也å¯ä»¥é€šè¿‡¾pÈ»Ÿå±žæ€§ã€ç±»è·¯å¾„上的'jndi.properties'æ–‡äšgã€åœ¨è°ƒç”¨JMXConnector.connect(Map environment)或者JMXConnectorFactory.connect(JMXServiceURL url, Map environment)æ–ÒŽ³•æ—¶ä¼ é€’çš„environment傿•°½{‰ä¸åŒæ–¹å¼æŒ‡å®šã€‚如果JNDI属性通过˜q™äº›æ–¹å¼æŒ‡å®šåQŒé‚£ä¹ˆJMXServiceURLä¸? å¯ä»¥ä½¿ç”¨½Ž€çŸçš„JNDIæ ¼å¼åQŒå³åªæŒ‡å®šJNDI path。以下是个例å:
Â
2.4 Remote Notification
   JSR
160定义的连接器å¯ä»¥æŽ¥æ”¶åˆ°è¿œ½E‹MBeanå‘é€çš„é€šçŸ¥ã€‚é€šçŸ¥è¢«ä¼ é€’çš„¾l†èŠ‚ä¾èµ–于连接器使用的åè®®ã€‚è¦æŽ¥æ”¶é€šçŸ¥åQŒå®¢æˆïL«¯å¿…é¡»è¦é€šè¿‡è°ƒç”¨
MBeanServerConnection.addNotificationListener(...)æ–ÒŽ³•æ¥æ³¨å†Œä¸€ä¸ªç›‘å¬å™¨åQŒè¿™ä¸ªæ–¹æ³•有两个é‡è²çš„版
本:
   ½W¬ä¸€ä¸ªç‰ˆæœ¬æŽ¥å—一个ObjectNameå®žä¾‹ä½œäØ“ç›‘å¬å™¨ï¼Œç”׃ºŽç›‘å¬å™¨æ˜¯˜qœç¨‹MBeanServerä¸çš„一个MBeanåQŒå› æ¤æ–¹æ³•ä¸çš„filterå’Œhandback傿•°å¿…é¡»è¢«ä¼ é€’åˆ°˜qœç¨‹çš„MBeanServeråQŒå› æ¤å®ƒä»¬å¿…™åÀL˜¯å¯ä»¥è¢«åºåˆ—化的ã€?br />  Â
å¦ä¸€ä¸ªç‰ˆæœ¬æŽ¥å—NotificationListener的实例作为监å¬å™¨ã€‚这个监å¬å™¨æ˜¯å®¢æˆïL«¯çš„æœ¬åœ°å¯¹è±¡ï¼Œè€Œä¸”监å¬å™¨å¯¹è±¡ä¸ä¼šè¢«ä¼ 递到˜qœç¨‹çš?
MBeanServeråQŒå› æ¤å®ƒä¹Ÿä¸å¿…是å¯ä»¥è¢«åºåˆ—化的。NotificationFilter是å¦è¢«ä¼ 递到˜qœç¨‹çš„MBeanServerå–决äº?
connector使用的å议,handback对象ä¸ä¼šè¢«ä¼ 递到˜qœç¨‹MBeanServer。在å¦ä¸€æ–šw¢åQŒè¿œ½E‹çš„MBeanå‘é€çš„通知必须是å¯ä»¥è¢«åºåˆ—
化的åQŒå› ä¸ºé€šçŸ¥ä¼šè¢«ä¼ é€’åˆ°å®¢æˆ·ç«¯ã€‚ä»¥ä¸‹æ˜¯åœ¨è¿œ½E‹çš„MBean上注册监å¬å™¨çš„例å:
Â
3 JMX Remoting Security
   JSR
160æä¾›äº†ä¸€¿U坿’æ‹”çš„è®¤è¯æœºåˆÓž¼Œå®ƒåŸºäºŽJMXAuthenticator接å£ã€‚JMXAuthenticator接å£ä¸åªåŒ…å«å¦‚下一个方法,它接å—从
客户端得到的íw«ä†¾è¯æ˜Žä¿¡æ¯ä½œäØ“å‚æ•°åQŒè¿”回javax.security.auth.Subject对象的一个实例ã€?/p>
   以下是在JMXConnectorServer ä¸ä‹É用JMXAuthenticator的例å:
   以下是在JMXConnectorä¸ä‹É用JMXAuthenticator的例å:
   当调用从JMXConnector 得到的MBeanServerConnection
接å£ä¸Šçš„æ–ÒŽ³•æ—Óž¼Œæœ€¾lˆå‘生在˜qœç¨‹MBeanServer的调用会以认è¯åŽçš„Subject
íw«ä†¾æ‰§è¡Œã€‚如果ä‹É用SecurityManageråQŒé‚£ä¹ˆè¿˜å¯ä»¥ä¸ÞZ¸åŒçš„Subject指定ä¸åŒçš„æƒé™ã€?/p>
1 DestinationResolver
   DestinationResolver接å£çš„作用是ž®†æŒ‡å®šçš„目的地åè§£æžä¸ºç›®çš„地实例。其定义如下åQ?/p>
Â Â Â å‚æ•°pubSubDomain用于指定是ä‹É用“å‘å¸?è®¢é˜…â€æ¨¡å¼ï¼ˆè§£æžåŽçš„目的地是TopicåQ‰ï¼Œ˜q˜æ˜¯ä½¿ç”¨â€œç‚¹å¯¹ç‚¹â€æ¨¡å¼ï¼ˆè§£æžåŽçš„目的地是QueueåQ‰ã€?/p>
Â
   CachingDestinationResolver接壾l§æ‰¿äº†DestinationResolveråQŒå¢žåŠ äº†¾~“å˜çš„功能,其接å£å®šä¹‰å¦‚下:
   在目的地失效的时候,removeFromCacheæ–ÒŽ³•会被调用åQ›åœ¨JMS provider失效的时候,clearCacheæ–ÒŽ³•会被调用ã€?br />
1.1 DynamicDestinationResolver
   DynamicDestinationResolver实现了DestinationResolver接å£ã€‚æ ¹æ®æŒ‡å®šçš„目的地ååQŒDynamicDestinationResolver会动æ€åˆ›å»ºç›®çš„地实例。针对JMS1.1规范åQŒå®ƒé‡‡ç”¨å¦‚下æ–ÒŽ³•创å¾ç›®çš„圎ͼš
1.2 JndiDestinationResolver
   JndiDestinationResolver¾l§æ‰¿è‡ªJndiLocatorSupportåQ?
åŒæ—¶å®žçŽ°äº†CachingDestinationResolver接å£ã€‚如果在JMS
providerä¸é…¾|®äº†é™æ€ç›®çš„地åQŒé‚£ä¹ˆJndiDestinationResolver通过JNDI查找的方å¼èŽ·å¾—ç›®çš„åœ°å®žä¾‹ã€?/p>
  Â
JndiDestinationResolverçš„fallbackToDynamicDestination属性用于指定在JNDI查找å¤ÞpÓ|åŽï¼Œæ˜¯å¦ä½?
用动æ€ç›®çš„地åQŒé»˜è®¤å€¼æ˜¯false。JndiDestinationResolverçš„cache属性用于指定是å¦å¯¹ç›®çš„地实例进行缓å˜ï¼Œé»˜è®¤å€¼æ˜¯
true�/p>
Â
1.3 BeanFactoryDestinationResolver
   BeanFactoryDestinationResolver实现了DestinationResolver接å£å’ŒBeanFactoryAware接å£ã€‚å®ƒä¼šæ ¹æ®æŒ‡å®šçš„目的地å从BeanFactory䏿Ÿ¥æ‰„¡›®çš„地实例。以下是相关的代ç :
Â
2 JmsAccessor
  Â
抽象¾c»JmsAccessor是JmsTemplateã€SimpleMessageListenerContainerå’?
DefaultMessageListenerContainer½{‰concrete
class的基¾c…R€‚JmsAccessorå®šä¹‰äº†å¦‚ä¸‹å‡ ä¸ªç”¨äºŽè®¿é—®JMSæœåŠ¡çš„å…±é€šå±žæ€§ã€?/p>
   JmsAccessoræä¾›äº†åˆ›å»ºConnectionå’ŒSession的方法,如下åQ?/p>
Â
2.1 JmsDestinationAccessor
  Â
抽象¾c»JmsDestinationAccessor¾l§æ‰¿è‡ªJmsAccessoråQŒå¢žåŠ äº†destinationResolverå’?
pubSubDomain属性。destinationResolver的默认值是DynamicDestinationResolver的实例,也就�
说默认采用动æ€ç›®çš„地解æžçš„æ–¹å¼ï¼›pubSubDomain用于指定是ä‹É用“å‘å¸?è®¢é˜…â€æ¨¡å¼è¿˜æ˜¯ä‹Éç”¨â€œç‚¹å¯¹ç‚¹â€æ¨¡å¼ï¼Œé»˜è®¤å€¼æ˜¯falseã€?br />
   JmsDestinationAccessoræä¾›äº†ç”¨äºŽè§£æžç›®çš„地的方法,如下åQ?/p>
2.2 AbstractJmsListeningContainer
   AbstractJmsListeningContainer¾l§æ‰¿è‡ªJmsDestinationAccessoråQŒä½œä¸ºæ‰€æœ‰Message
Listener Container的公共基¾c…R€‚å®ƒä¸»è¦æä¾›äº†JMS
connection的生命周期管ç†çš„功能åQŒä½†æ˜¯æ²¡æœ‰å¯¹æ¶ˆæ¯æŽ¥æ”¶çš„æ–¹å¼ï¼ˆä¸ÕdŠ¨æŽ¥æ”¶æ–¹å¼æˆ–è€…å¼‚æ¥æŽ¥æ”¶æ–¹å¼ï¼‰½{‰åšä»ÖM½•å‡å®šã€‚该¾cÖM¸»è¦çš„属性如下:
   clientId通常用于æŒä¹…订阅åQ›sharedConnectionä¿å˜äº†è¢«å…׃ínçš„JMS connectionã€?/p>
Â
   该类定义了如下的抽象æ–ÒŽ³•åQŒä»¥ä¾¿å¾cÕd¯ä»¥å†³å®šæ˜¯å¦ä‹É用共享的JMS connectionã€?/p>
Â
2.3 AbstractMessageListenerContainer
   AbstractMessageListenerContainer¾l§æ‰¿è‡ªAbstractJmsListeningContaineråQŒä¹Ÿæ˜¯ä½œä¸ºæ‰€æœ‰Message Listener Container的公共基¾c…R€‚该¾cÖM¸»è¦çš„属性如下:
   destination用于指定接收消æ¯çš„目的地ã€?br />    messageListenerç”¨äºŽæŒ‡å®šå¤„ç†æ¶ˆæ¯çš„listener。对于messageListeneråQŒå®ƒæ—¢å¯ä»¥æ˜¯½W¦åˆJMS规范çš? javax.jms.MessageListeneråQŒä¹Ÿå¯ä»¥æ˜¯Springç‰ÒŽœ‰çš? org.springframework.jms.listener.SessionAwareMessageListenerã€? SessionAwareMessageListener的定义如下:
   跟javax.jms.MessageListener相比åQŒè¿™ä¸ªæŽ¥å£çš„onMessageæ–ÒŽ³•å¢žåŠ äº†ä¸€ä¸ªSession ¾cÕdž‹çš„傿•ŽÍ¼Œå¯ä»¥é€šè¿‡˜q™ä¸ªsessionå‘é€å›žå¤æ¶ˆæ¯ï¼ˆreply messageåQ‰ã€?/p>
   如果使用了SessionAwareMessageListener ¾cÕdž‹çš„message
listeneråQŒé‚£ä¹ˆexposeListenerSession傿•°æŒ‡å®šäº†ä¼ å…¥onMessageæ–ÒŽ³•çš„session傿•°æ˜¯å¦æ˜¯åˆ›å»ÞZº†
MessageConsumerçš„sessionåQŒé»˜è®¤å€¼æ˜¯true。如果是falseåQŒé‚£ä¹?
AbstractMessageListenerContainer会在connection上新å»ÞZ¸€ä¸ªsessionåQŒåÆˆä¼ å…¥onMessageæ–ÒŽ³•ã€?br />
2.4 AbstractPollingMessageListenerContainer
   AbstractPollingMessageListenerContainer¾l§æ‰¿è‡ªAbstractMessageListenerContaineråQŒå®ƒæä¾›äº†å¯¹äºŽä¸»åŠ¨æŽ¥æ”¶æ¶ˆæ?polling)的支æŒï¼Œä»¥åŠæ”¯æŒå¤–部的事务管ç†ã€?/p>
   如果使用“å‘å¸?è®¢é˜…â€æ¨¡å¼ï¼Œé‚£ä¹ˆpubSubNoLocal 属性指定通过æŸä¸ª˜qžæŽ¥å‘é€åˆ°æŸä¸ªTopic的消æ¯ï¼Œæ˜¯å¦åº”该被投递回˜q™ä¸ª˜qžæŽ¥ã€?/p>
   receiveTimeout属性用于指定调用MessageConsumerçš„receiveæ–ÒŽ³•æ—¶çš„‘…æ—¶æ—‰™—´åQŒé»˜è®¤å€¼æ˜¯1¿U’ã€‚éœ€è¦æ³¨æ„的是,˜q™ä¸ªå€¼åº”该比transactionManager 䏿Œ‡å®šçš„事务‘…æ—¶æ—‰™—´ç•¥å°ã€?/p>
  Â
通常情况下,应该为transactionManager讄¡½®ä¸€ä¸?
org.springframework.transaction.jta.JtaTransactionManager的实例,æ¤å¤–也è¦è®„¡½®ä¸€ä¸ªæ”¯æŒ?
XAçš„ConnectionFactoryã€‚éœ€è¦æ³¨æ„的是,XA 事务å¯ÒŽ€§èƒ½æœ‰è¾ƒå¤§çš„å½±å“ã€?br />
Â Â Â å¦‚æžœåªæ˜¯å¸Œæœ›ä½¿ç”¨local JMS
transactionåQŒé‚£ä¹ˆåªè¦è®¾¾|®sessionTransacted为true或者ä‹É用JmsTransactionManagerå›_¯ã€‚实际上åQ?
如果讄¡½®äº†éžJTAçš„transactionManageråQŒé‚£ä¹ˆsessionTransacted属性会自动被设¾|®æˆtrueã€?br />
   ç”׃ºŽlocal JMS transactionæ— æ³•åŒå…¶å®ƒlocal transactionåQˆä¾‹å¦‚local database
transactionåQ‰è¿›è¡Œåè°ƒï¼Œå› æ¤å®¢æˆ·ç«¯ç¨‹åºå¯èƒ½éœ€è¦å¯¹é‡å‘的消æ¯è¿›è¡Œæ£€æŸ¥ã€‚JMSè§„èŒƒè¦æ±‚åQšJMS
provider应该ž®†é‡å‘消æ¯çš„JMSRedelivered属性设¾|®äØ“trueã€?br />
2.5 SimpleMessageListenerContainer
  Â
SimpleMessageListenerContainer¾l§æ‰¿è‡ªAbstractMessageListenerContaineråQŒä‹Éç”¨å¼‚æ¥æ–¹å¼?
接收消æ¯åQˆä¹Ÿž®±æ˜¯é€šè¿‡MessageConsumer上注册MessageListenerçš„æ–¹å¼æŽ¥æ”¶æ¶ˆæ¯ï¼‰ã€‚该¾cÖM¸»è¦çš„属性如下:
   如果使用“å‘å¸?è®¢é˜…â€æ¨¡å¼ï¼Œé‚£ä¹ˆpubSubNoLocal 属性指定通过æŸä¸ª˜qžæŽ¥å‘é€åˆ°æŸä¸ªTopic的消æ¯ï¼Œæ˜¯å¦åº”该被投递回˜q™ä¸ª˜qžæŽ¥ã€?/p>
Â
   SimpleMessageListenerContainerå…许创å¾å¤šä¸ªSessionå’ŒMessageConsumeræ¥æŽ¥æ”¶æ¶ˆæ¯ã€‚具体的个数ç”? concurrentConsumerså±žæ€§æŒ‡å®šã€‚éœ€è¦æ³¨æ„çš„æ˜¯ï¼Œåº”è¯¥åªæ˜¯åœ¨Destination为Queue的时候æ‰ä½¿ç”¨å¤šä¸ª MessageConsumeråQˆQueueä¸çš„一个消æ¯åªèƒ½è¢«ä¸€ä¸ªConsumer接收åQ‰ï¼Œè™½ç„¶ä½¿ç”¨å¤šä¸ªMessageConsumer会æé«˜æ¶ˆæ¯å¤„ç? 的性能åQŒä½†æ˜¯æ¶ˆæ¯å¤„ç†çš„™åºåºå´å¾—ä¸åˆ°ä¿è¯åQšæ¶ˆæ¯è¢«æŽ¥æ”¶çš„顺åºä»ç„¶æ˜¯æ¶ˆæ¯å‘逿—¶çš„顺åºï¼Œä½†æ˜¯ç”׃ºŽæ¶ˆæ¯å¯èƒ½ä¼šè¢«òq¶å‘处ç†åQŒå› æ¤æ¶ˆæ¯å¤„ç†çš„™åºåºå¯èƒ½å’Œæ¶ˆæ¯å‘é€çš„ ™åºåºä¸åŒã€‚æ¤å¤–,ä¸åº”该在Destination为Topic的时候ä‹É用多个MessageConsumeråQŒè¿™æ˜¯å› 为多ä¸? MessageConsumerä¼šæŽ¥æ”¶åˆ°åŒæ ·çš„æ¶ˆæ¯ã€?/p>
   SimpleMessageListenerContainer创å¾çš„Sessionå’ŒMessageConsumer分别ä¿å˜åœ¨sessionså’Œconsumers属性ä¸ã€?/p>
  Â
taskExecutor属性的默认值是nullåQŒä¹Ÿž®±æ˜¯è¯ß_¼Œå¯¹MessageListeneråQˆæˆ–è€?
SessionAwareMessageListeneråQ‰çš„回调是在MessageConsumer的内部线½E‹ä¸æ‰§è¡Œã€‚如果指定了
taskExecutoråQŒé‚£ä¹ˆå›žè°ƒæ˜¯åœ¨TaskExecutor内部的线½E‹ä¸æ‰§è¡Œã€‚以下是相关的代ç :
Â Â Â éœ€è¦æ³¨æ„的是,如果指定了taskExecutoråQŒé‚£ä¹ˆæ¶ˆæ¯åœ¨è¢«taskExecutor内部的线½E‹å¤„ç†å‰åQŒå¯èƒ½å·²¾l被¼‹®è®¤˜q‡äº†åQˆå¤–层的 onMessageæ–ÒŽ³•å¯èƒ½å·²ç»æ‰§è¡Œ¾l“æŸäº†ï¼‰ã€‚å› æ¤å¦‚æžœä‹É用事务Session或者Session.CLIENT_ACKNOWLEDGE¾cÕdž‹çš„确认模 å¼ï¼Œé‚£ä¹ˆå¯èƒ½ä¼šå¯¼è‡´é—®é¢˜ã€?/p>
Â
  Â
该类的sharedConnectionEnabledæ–ÒŽ³•åQˆåœ¨AbstractJmsListeningContainerä¸å®šä¹‰ï¼‰æ€ÀL˜¯˜q”回trueåQ?
å› æ¤SimpleMessageListenerContainer会ä‹É用共享的JMS connectionã€?br />
2.6 DefaultMessageListenerContainer
  Â
DefaultMessageListenerContainer¾l§æ‰¿è‡?
AbstractPollingMessageListenerContaineråQŒä¸»è¦ä‹Éç”¨åŒæ¥çš„æ–¹å¼æŽ¥æ”¶æ¶ˆæ¯åQˆä¹Ÿž®±æ˜¯é€šè¿‡å¾ªçŽ¯è°ƒç”¨
MessageConsumer.receiveçš„æ–¹å¼æŽ¥æ”¶æ¶ˆæ¯ï¼‰ã€‚该¾cÖM¸»è¦çš„属性如下:
   跟SimpleMessageListenerContainerä¸€æ øP¼ŒDefaultMessageListenerContainer也支æŒåˆ›å»ºå¤šä¸? Sessionå’ŒMessageConsumeræ¥æŽ¥æ”¶æ¶ˆæ¯ã€‚è·ŸSimpleMessageListenerContainerä¸åŒçš? 是,DefaultMessageListenerContainer创å¾äº†concurrentConsumers所指定个数çš? AsyncMessageListenerInvokeråQˆå®žçŽîCº†SchedulingAwareRunnable接å£åQ‰ï¼Œòq¶äº¤¾l? taskExecutor˜q行ã€?/p>
  Â
maxMessagesPerTask属性的默认值是Integer.MIN_VALUEåQŒä½†æ˜¯å¦‚果设¾|®çš„taskExecutoråQˆé»˜è®¤å€¼æ˜¯
SimpleAsyncTaskExecutoråQ‰å®žçŽîCº†SchedulingTaskExecutor接å£òq¶ä¸”å…?
prefersShortLivedTasksæ–ÒŽ³•˜q”回trueåQˆä¹Ÿž®±æ˜¯è¯´è¯¥TaskExecutorå€‘Ö‘äºŽçŸæœŸä“Q务)åQŒé‚£ä¹?
maxMessagesPerTask属性会自动被设¾|®äØ“10ã€?br />
  Â
如果maxMessagesPerTask属性的值å°äº?åQŒé‚£ä¹ˆAsyncMessageListenerInvoker.runæ–ÒŽ³•会在循环ä¸åå¤å°è¯?
接收消æ¯åQŒåƈ在接收到消æ¯åŽè°ƒç”¨MessageListeneråQˆæˆ–者SessionAwareMessageListeneråQ‰ï¼›å¦‚æžœ
maxMessagesPerTask属性的å€ég¸ž®äºŽ0åQŒé‚£ä¹ˆAsyncMessageListenerInvoker.runæ–ÒŽ³•里最多会ž®è¯•接收消æ¯
maxMessagesPerTask‹Æ¡ï¼Œæ¯æ¬¡æŽ¥æ”¶æ¶ˆæ¯çš„超时时间由其父¾c?
AbstractPollingMessageListenerContainerçš„receiveTimeout属性指定。如果在˜q™äº›ž®è¯•ä¸éƒ½æ²¡æœ‰æŽ¥æ”¶
到消æ¯ï¼Œé‚£ä¹ˆAsyncMessageListenerInvokerçš„idleTaskExecutionCount属性会被ç¯åŠ ã€‚åœ¨runæ–ÒŽ³•执行å®?
毕å‰ä¼šå¯¹idleTaskExecutionCount˜q›è¡Œ‹‚€æŸ¥ï¼Œå¦‚æžœè¯¥å€ÆD¶…˜q‡äº†
DefaultMessageListenerContainer.idleTaskExecutionLimitåQˆé»˜è®¤å€?åQ‰ï¼Œé‚£ä¹ˆ˜q™ä¸ª
AsyncMessageListenerInvokerå¯èƒ½ä¼šè¢«é”€æ¯ã€?/p>
  Â
所有AsyncMessageListenerInvoker实例都ä¿å˜åœ¨scheduledInvokersä¸ï¼Œå®žä¾‹çš„个数å¯ä»¥åœ¨
concurrentConsumerså’ŒmaxConcurrentConsumers之间‹¹®åŠ¨ã€‚è·Ÿ
SimpleMessageListenerContainerä¸€æ øP¼Œåº”è¯¥åªæ˜¯åœ¨Destination为Queue的时候æ‰ä½¿ç”¨å¤šä¸ª
AsyncMessageListenerInvoker实例�/p>
Â
   cacheLevel属性用于指定是å¦å¯¹JMS资溘q›è¡Œ¾~“å˜åQŒå¯é€‰çš„值是CACHE_NONE = 0ã€CACHE_CONNECTION = 1ã€CACHE_SESSION = 2ã€CACHE_CONSUMER = 3å’ŒCACHE_AUTO = 4。默认情况下åQŒå¦‚æžœtransactionManager属性ä¸ä¸ºnullåQŒé‚£ä¹ˆcacheLevel被自动设¾|®äØ“CACHE_NONEåQˆä¸˜q›è¡Œ¾~? å˜ï¼‰åQŒå¦åˆ™cacheLevel被自动设¾|®äØ“CACHE_CONSUMERã€?/p>
   如果cacheLevel属性值大于ç‰äºŽCACHE_CONNECTIONåQŒé‚£ä¹ˆsharedConnectionEnabledæ–ÒŽ³•åQˆåœ¨AbstractJmsListeningContainerä¸å®šä¹‰ï¼‰˜q”回trueåQŒä¹Ÿž®±æ˜¯è¯´ä‹É用共享的JMS˜qžæŽ¥ã€?/p>
Â
Â
3 SingleConnectionFactory
  Â
SingleConnectionFactory实现了ConnectionFactory接å£åQŒå…¶createConnectionæ–ÒŽ³•æ€ÀL˜¯˜q”回相åŒçš?
Connection。å¯ä»¥åœ¨SingleConnectionFactoryçš„æž„é€ å‡½æ•îC¸ä¼ å…¥Connection对象或è€?
ConnectionFactory对象åQŒç”¨æ¥åˆ›å»ø™¢«ä»£ç†çš„连接对象ã€?
SingleConnectionFactory.createConnectionæ–ÒŽ³•˜q”回的连接是个代ç†ï¼Œå®ƒå¿½ç•¥äº†å¯¹stopå’Œcloseæ–ÒŽ³•的调ç”?
åQˆè¿žæŽ¥ä¼šåœ¨SingleConnectionFactory.destroyæ–ÒŽ³•ä¸å…³é—)ã€?/p>
   SingleConnectionFactoryçš„reconnectOnExceptionå±žæ€§ç”¨æ¥æŒ‡å®šæ˜¯å¦åœ¨˜qžæŽ¥æŠ›å‡ºJMSException的时候,对连接进行釾|®ï¼Œé‡ç½®åŽå¦‚æžœå†è°ƒç”¨createConnectionæ–ÒŽ³•åQŒé‚£ä¹ˆä¼š˜q”回一个新的连接ã€?/p>
  Â
éœ€è¦æ³¨æ„的是,AbstractJmsListeningContainer¾cÈš„抽象æ–ÒŽ³•sharedConnectionEnabled指定了是å¦åœ¨
message listener container内部使用å…׃ínçš„JMS˜qžæŽ¥ã€‚å› æ¤é€šå¸¸æƒ…况下ä¸éœ€è¦äØ“å•独的message listener
container讄¡½®SingleConnectionFactoryåQˆåŠå…¶å¾c»ï¼‰åQ›å¦‚果希望在ä¸åŒçš„message listener
container之间å…׃ínJMS˜qžæŽ¥åQŒé‚£ä¹ˆå¯ä»¥è€ƒè™‘使用SingleConnectionFactoryã€?br />
3.1 CachingConnectionFactory
   CachingConnectionFactory¾l§æ‰¿è‡ªSingleConnectionFactoryåQŒå¢žåŠ äº†å¯¹Sessionå’ŒMessageProducer¾~“å˜çš„功能。该¾cÖM¸»è¦çš„属性如下:
   sessionCacheSize属性指定了被缓å˜çš„Session实例的个敎ͼˆé»˜è®¤å€¼æ˜¯1åQ‰ï¼Œä¹Ÿå°±æ˜¯è¯´åQŒå¦‚æžœåŒæ—¶è¯·æ±‚çš„Session个数大于sessionCacheSizeåQŒé‚£ä¹ˆè¿™äº›Sessionä¸ä¼šè¢«ç¼“å˜ï¼Œè€Œæ˜¯æ£å¸¸çš„被创å¾å’Œé”€æ¯ã€?/p>
   cacheProducers属性指定了是å¦å¯¹MessageProducer˜q›è¡Œ¾~“å˜åQŒé»˜è®¤å€¼æ˜¯trueã€?/p>
实战一 , 实战二介¾l了ActiveMQ的基本概念和é…置方å¼.
本篇ž®†é€šè¿‡ä¸€ä¸ªå®žä¾‹ä»‹¾lä‹É用springå‘é€?消费topic, queue¾cÕdž‹æ¶ˆæ¯çš„æ–¹æ³? 䏿‡‚topicå’Œqueueçš„google ä¹?
如图½C? TOPICå’ŒQUEUE分别代表一个topic和一个queue消æ¯é€šé“.
ž®±åƒå¯¹orm, web的支æŒä¸€æ ? springåŒæ ·æ”¯æŒjms, 为整åˆjms到已有的™å¹ç›®æä¾›äº†å¾ˆå¤šä¾¿åˆ©çš„æ–ÒŽ³•. 本篇主è¦è®²å®žæˆ? 是所以先从酾|®å¼€å§? springé…ç½®jms基本上需è¦?个部åˆ?
下é¢ä»¥å®žä¾‹çš„æ–¹å¼ä»‹ç»ä¸Šé¢8个部åˆ?
brokerURL是指è¦è¿žæŽ¥çš„activeMQ server的地å€, activeMQæä¾›äº†å¤š¿UbrokerURL, 集体å¯å‚è§æ–‡æ¡?一般我们ä‹É用嵌套的ActiveMQ server. é…置如下, ˜q™ä¸ªé…置使用消æ¯çš„å˜å‚¨æœºåˆ? æœåС噍é‡å¯ä¹Ÿä¸ä¼šä¸¢å¤±æ¶ˆæ¯.
åœ¨å®žä¾‹ä¸æˆ‘们使用了两¿Udestination
MessageConverter实现的是org.springframework.jms.support.converter.MessageConverter接å£, æä¾›æ¶ˆæ¯çš„è{æ¢åŠŸèƒ? DefaultMessageConverter的实现è§é™„äšg.
实例拥有两个消æ¯ç”Ÿäñ”è€? 消æ¯ç”Ÿäñ”者都是POJO, 实现è§é™„ä»?
TOPICé€šé“æœ‰ä¸¤ä¸ªæ¶ˆæ¯æ¶ˆè´¹è€? QUEUEæœ‰ä¸€ä¸ªæ¶ˆæ¯æ¶ˆè´¹è€?/p>
æ¯ä¸€ä¸ªæ¶ˆæ¯æ¶ˆè´¹è€…都对应一个MessageListener
æœ‰å‡ ä¸ªMessageListeneræ—¢æœ‰å‡ ä¸ªMessageListenerContainer
写springé…置文äšg的时å€? è¦æŠŠMessageProducer, MessageConsumer,MessageListener,MessageListenerContainerå‡ ä¸ªåœ°æ–¹å¼„æ¸…æ¥?
上一½‹‡http://www.javaeye.com/topic/15317介ç»äº†ActiveMQ5.0的安装,˜q™ä¸€½‹‡å°†ä»‹ç»çš„é…¾|®ã€‚ActiveMQ包å«äº†å¾ˆå¤šfeaturesåQˆè¯¦è§?a target="_blank">http://activemq.apache.org/features.html åQ‰ï¼Œ
ä¸åŒçš„需求,ä¸åŒçš„环境,需è¦ä¸åŒçš„featuresåQŒå½“焉™œ€è¦ä¸åŒçš„é…置。在˜q™é‡Œæˆ‘åªå†™äº†æœ€åŸºæœ¬çš„é…¾|®ï¼Œ½Ž—æ˜¯æŠ›ç –äº†ï¼Œå¸Œæœ›å¼•å‡ºæ›´å¤šå…³äºŽActiveMQ的高¾U§é…¾|®ã€?br />
å‡è®¾å·²ç»æ£ç¡®å®‰è£…ActiveMQ5.0åQŒåŒæ—¶åŠå…¶IP地å€ä¸?92.168.1.148åQŒå…·ä½“ä‹É用时å¯ä»¥æ”¹äؓ自己的IP。下é¢è®²è§£çš„é…置实现的features如下åQ?/p>
ActiveMQ默认使用的是XMLæ ¼å¼é…ç½®åQŒä»Ž4.0版本开始用MBean的方å¼å®žçްXMLé…ç½®åQŒé…¾|®æ–‡ä»¶åœ¨${activemq.home}/conf目录下,文äšgå䨓activemq.xml。最新的默认é…ç½®è§?br /> http://svn.apache.org/repos/asf/activemq/trunk/assembly/src/release/conf/activemq.xml 。下é¢äØ“æœ¬ç¯‡æ–‡ç« ä½¿ç”¨çš„é…¾|®ï¼ŒåŠé‡è¦éƒ¨åˆ†çš„解释ã€?/p>
关于XMLé…ç½®ä¸å…ƒç´ 的具体信æ¯å¯ä»¥å‚è€?a >http://activemq.apache.org/xbean-xml-reference-50.html 下é¢ä»‹ç»æœ¬ç¯‡é…置使用的一些é‡è¦å…ƒç´ ã€?
ActiveMQ支æŒ3ä¸ä¸åŒçš„分命{–ç•¥åQˆé¿å…翻译了以åŽè¯¯è§£åQŒè¿™é‡Œç”¨åŽŸæ–‡åQ‰ï¼š
ActiveMQ支æŒ6¿Uæ¢å¤ç–略,å¯ä»¥è‡ªè¡Œé€‰æ‹©ä½¿ç”¨ä¸åŒçš„ç–ç•?/p>
http://activemq.apache.org/persistence 讲解了关于persistence的信æ¯ã€‚ActiveMQ5.0使用AMQ Message Store æŒä¹…化消æ¯ï¼Œ˜q™ç§æ–¹å¼æä¾›äº†å¾ˆå¥½çš„æ€§èƒ½åQˆThe AMQ Message Store is an embeddable transactional message storage solution that is extremely fast and reliable.åQ?默认使用该å˜å‚¨æ–¹å¼å³å¯ï¼Œå¦‚果想ä‹É用JDBCæ¥å˜å‚¨ï¼Œå¯ä»¥æŸ¥æ‰¾æ–‡æ¡£é…ç½®ã€?nbsp;
æœ¬ç¯‡æ–‡ç« åªæä¾›äº†åŸºæœ¬é…置信æ¯ã€‚å¦‚æžœéœ€è¦æ›´å¤šçš„æ–‡ç« åQŒå¯ä»¥æŸ¥çœ‹ActiveMQ的文档ã€?/p>
讲了安装和简å•çš„é…ç½®åQŒä¸‹ä¸€½‹‡å°†ä»‹ç»å’ŒSping的整åˆï¼Œä»¥åŠå¤šä¸ªqueueåQŒå¤šä¸ªtopicåQŒå¤šä¸ªproduceråQŒå¤šä¸ªconsumer的酾|®ï¼Œä½¿ç”¨ã€?/p>
ActiveMQ 是开æºçš„JMS实现åQŒGeronimo应用æœåŠ¡å™¨å°±æ˜¯ä‹É用的ActiveMQæä¾›JMSæœåŠ¡ã€‚ActiveMQ5.0相比以å‰ç‰ˆæœ¬æä¾›äº†ä¸€äº›éžå¸¸æœ‰ç”¨çš„æ–°åŠŸèƒ½ï¼š
鉴于目å‰å…³äºŽActiveMQ5.0çš„æ–‡ç« æ¯”è¾ƒå°‘åQŒæ•…准备写一¾pÕdˆ—ActiveMQçš„ä‹É用方é¢çš„æ–‡ç« 。本½‹‡å…ˆä»Žå®‰è£…开始ã€?nbsp;
ActiveMQ默认使用的TCP˜qžæŽ¥ç«¯å£æ˜?1616, 通过查看该端å£çš„ä¿¡æ¯å¯ä»¥‹¹‹è¯•ActiveMQæ˜¯å¦æˆåŠŸå¯åЍ
ActiveMQ5.0版本默认å¯åЍæ—Óž¼Œå¯åŠ¨äº†å†…¾|®çš„jettyæœåŠ¡å™¨ï¼Œæä¾›ä¸€ä¸ªdemo应用和用于监控ActiveMQçš„admin应用ã€?/p>
adminåQ?a >http://127.0.0.1:8161/admin/
demoåQ?a >http://127.0.0.1:8161/demo/
点击demo应用ä¸çš„“ Market data publisher ”åQŒå°±ä¼šå‘一些测试的消æ¯ã€‚è{到admin™åµé¢çš„topics menu下é¢åQˆqueueå’Œtopicçš„åŒºåˆ«è§ http://andyao.javaeye.com/blog/153173 åQ‰ï¼Œå¯ä»¥çœ‹åˆ°æ¶ˆæ¯åœ¨å¢žé•Ñ€?/p>
ActiveMQ5.0的酾|®æ–‡ä»¶åœ¨/path/to/activemq/conf目录下é¢ã€‚主è¦é…¾|®æ–‡ä»¶äØ“activemq.xmlåQŒå…·ä½“çš„é…ç½®ž®†åœ¨åŽç®‹æ–‡ç« ä¸è¯¦¾l†è¯´æ˜Žã€?/p>