<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>涂0实验室 &#187; jms</title>
	<atom:link href="http://www.sulong.info/archives/tag/jms/feed" rel="self" type="application/rss+xml" />
	<link>http://www.sulong.info</link>
	<description>一个程序员的成长之路</description>
	<lastBuildDate>Fri, 27 Aug 2010 01:54:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>ActiveMQ使用经验</title>
		<link>http://www.sulong.info/archives/207</link>
		<comments>http://www.sulong.info/archives/207#comments</comments>
		<pubDate>Thu, 18 Jun 2009 09:56:41 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[经验]]></category>
		<category><![CDATA[jms]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=207</guid>
		<description><![CDATA[ActiveMQ是apache的一个开源JMS服务器，不仅具备标准JMS的功能，还有很多额外的功能。公司里引入ActiveMQ后，ActiveMQ成里我们公司业务系统中最重要的一个环节。所有应用都通过jms集成，如果ActiveMQ出了故障，整个系统就瘫痪了。因此，头对ActiveMQ的性能，可靠性，以及如何正确使用，是非常的关心的，而我就被指派来做关于ActiveMQ的调研，本文对此做了些总结。 1 使用jms需要注意的问题 一下所述的问题，不仅是对ActiveMQ，对于其他的JMS也一样有效。 1.1 不要频繁的建立和关闭连接 JMS使用长连接方式，一个程序，只要和JMS服务器保持一个连接就可以了，不要频繁的建立和关闭连接。频繁的建立和关闭连接，对程序的性能影响还是很大的。这一点和jdbc还是不太一样的。 1.2 Connection的start()和stop()方法代价很高 JMS的Connection的start()和stop()方法代价很高，不能经常调用。我们试用的时候，写了个jms的connection pool，每次将connection取出pool时调用start()方法，归还时调用stop()方法，然而后来用jprofiler发现，一般的cpu时间都耗在了这两个方法上。 1.3 start()后才能收消息 Connection的start()方法调用后，才能收到jms消息。如果不调用这个方法，能发出消息，但是一直收不到消息。不知道其它的jms服务器也是这样。 1.4 显示关闭Session 如果忘记了最后关闭Connection或Session对象，都会导致内存泄漏。这个在我测试的时候也发现了。本来以为关闭了Connection，由这个Connection生成的Session也会被自动关闭，结果并非如此，Session并没有关闭，导致内存泄漏。所以一定要显示的关闭Connection和Session。 1.5 对Session做对象池 对Session做对象池，而不是Connection。Session也是昂贵的对象，每次使用都新建和关闭，代价也非常高。而且后来我们发现，原来Connection是线程安全的，而Session不是，所以后来改成了对Session做对象池，而只保留一个Connection。 2 集群 ActiveMQ有强大而灵活的集群功能，但是使用起来还是会有很多陷阱。 2.1 broker cluster和 master-slave ActiveMQ可以做broker的集群，也可以做master-slave方式的集群。前者能在多个broker之前fail-over和load-balance，但是在某个节点出故障时，可能导致消息丢失；而后者能实时备份消息，和fail-over，但是不能load-balance。broker cluser的方式，在一个broker上发送的消息可以在其它的broker上收到。当一个broker失效时，客户端可以自动的转到别的broker上运行，多个broker可以同时提供服务，但是消息只存储在一个broker上，如果那个broker失效了，那么客户端直到它重新启动后才能收到该broker上的消息，假如很不幸，那个broker的存储介质坏了，那么消息就丢失掉了。 Master-slave方式中，只有master提供服务，slave只是实时的备份master的数据，所以消息不会丢失。当master失效时，slave会自动升为master，客户端会自动转到slave上工作，所以能fail-over。由于只有master提供服务，所以不能将负载分到多个broker上。 其实单个broker的性能已经是相当的惊人了，在我们公司的机器上能达到每秒收发4000个消息，没个消息4K字节这样的速度，足够公司目前的需要了，而公司并不希望丢失任何数据，所以我们选择使用master-slave模式。 2.2 多种master-slave模式 master-slave也有多种实现方式。它们的不同只是在共享数据和锁机制上。 2.2.1 Pure master-slave Pure master-slave，显示的在配置文件中指定一个broker做为另一个broker的slave。运行时，slave同过网络自动从master出复制数据，同时在和master失去连接时自动升级为master。当master失效，slave成为master后，如果要让原先的master重新投入运行，需要停掉运行中的slave(现在升级为master了)，手动复制slave中的数据到master中。再重新启动master和slave。这种方式最简单，效率也不错，但是只能有两台做集群，只能fail-over一次，而且需要停机回复master-slave结构。 2.2.2 JDBC master-slave 这种方式不需要特殊的配置，只要让所有的节点都把数据存储到同一个数据库中。先拿到数据库表的锁的节点成为master，一旦它失效了，其它的节点获得锁，就可以成为master。因为数据通过数据库共享，放在一个地方，不需要停机恢复master-slave。这种方式，需要额外的数据库服务器，如果数据库失效了，那么就全失效了，而且速度不是很快。我们在用mysql测试时，并没有成功，master失效后，其他的节点始终没有升级成slave，可能是数据库配置的问题。 2.2.3 Share file master-slave 这种方式类似于前者，也不需要特别的配置，只是通过共享文件系统来共享数据，靠文件锁实现只有一台成为master。共享文件系统的方式有很多，我们测试了nfs v4 (v3有bug，不行)， 最终在稳定性，效率等方面不是很满意，可能是通过网络太慢了。 测试过众多master-slave模式后发现，pure方式管理起来麻烦，jdbc方式成本高，效率低，share file方式需要高性能的共享文件，都有缺点。鉴于单台activeMQ很可靠，而我们的基础平台组愿意用硬件备份，最终还是决定不用master-slave了，也不用broker cluster，就用单台，通过硬件冗余保证数据不会丢失，并找另外一台刀片机做冷备，在主服务器失效时顶替。]]></description>
			<content:encoded><![CDATA[<p>ActiveMQ是apache的一个开源JMS服务器，不仅具备标准JMS的功能，还有很多额外的功能。公司里引入ActiveMQ后，ActiveMQ成里我们公司业务系统中最重要的一个环节。所有应用都通过jms集成，如果ActiveMQ出了故障，整个系统就瘫痪了。因此，头对ActiveMQ的性能，可靠性，以及如何正确使用，是非常的关心的，而我就被指派来做关于ActiveMQ的调研，本文对此做了些总结。</p>
<h2>1 使用jms需要注意的问题</h2>
<p>一下所述的问题，不仅是对ActiveMQ，对于其他的JMS也一样有效。</p>
<h3>1.1 不要频繁的建立和关闭连接</h3>
<p>JMS使用长连接方式，一个程序，只要和JMS服务器保持一个连接就可以了，不要频繁的建立和关闭连接。频繁的建立和关闭连接，对程序的性能影响还是很大的。这一点和jdbc还是不太一样的。</p>
<h3>1.2 Connection的start()和stop()方法代价很高</h3>
<p>JMS的Connection的start()和stop()方法代价很高，不能经常调用。我们试用的时候，写了个jms的connection pool，每次将connection取出pool时调用start()方法，归还时调用stop()方法，然而后来用jprofiler发现，一般的cpu时间都耗在了这两个方法上。</p>
<h3>1.3 start()后才能收消息</h3>
<p>Connection的start()方法调用后，才能收到jms消息。如果不调用这个方法，能发出消息，但是一直收不到消息。不知道其它的jms服务器也是这样。</p>
<h3>1.4 显示关闭Session</h3>
<p>如果忘记了最后关闭Connection或Session对象，都会导致内存泄漏。这个在我测试的时候也发现了。本来以为关闭了Connection，由这个Connection生成的Session也会被自动关闭，结果并非如此，Session并没有关闭，导致内存泄漏。所以一定要显示的关闭Connection和Session。</p>
<h3>1.5 对Session做对象池</h3>
<p>对Session做对象池，而不是Connection。Session也是昂贵的对象，每次使用都新建和关闭，代价也非常高。而且后来我们发现，原来Connection是线程安全的，而Session不是，所以后来改成了对Session做对象池，而只保留一个Connection。</p>
<h2>2 集群</h2>
<p>ActiveMQ有强大而灵活的集群功能，但是使用起来还是会有很多陷阱。</p>
<h3>2.1 broker cluster和 master-slave</h3>
<p>ActiveMQ可以做broker的集群，也可以做master-slave方式的集群。前者能在多个broker之前fail-over和load-balance，但是在某个节点出故障时，可能导致消息丢失；而后者能实时备份消息，和fail-over，但是不能load-balance。broker cluser的方式，在一个broker上发送的消息可以在其它的broker上收到。当一个broker失效时，客户端可以自动的转到别的broker上运行，多个broker可以同时提供服务，但是消息只存储在一个broker上，如果那个broker失效了，那么客户端直到它重新启动后才能收到该broker上的消息，假如很不幸，那个broker的存储介质坏了，那么消息就丢失掉了。<br />
Master-slave方式中，只有master提供服务，slave只是实时的备份master的数据，所以消息不会丢失。当master失效时，slave会自动升为master，客户端会自动转到slave上工作，所以能fail-over。由于只有master提供服务，所以不能将负载分到多个broker上。<br />
其实单个broker的性能已经是相当的惊人了，在我们公司的机器上能达到每秒收发4000个消息，没个消息4K字节这样的速度，足够公司目前的需要了，而公司并不希望丢失任何数据，所以我们选择使用master-slave模式。</p>
<h3>2.2 多种master-slave模式</h3>
<p>master-slave也有多种实现方式。它们的不同只是在共享数据和锁机制上。</p>
<h4>2.2.1 Pure master-slave</h4>
<p>Pure master-slave，显示的在配置文件中指定一个broker做为另一个broker的slave。运行时，slave同过网络自动从master出复制数据，同时在和master失去连接时自动升级为master。当master失效，slave成为master后，如果要让原先的master重新投入运行，需要停掉运行中的slave(现在升级为master了)，手动复制slave中的数据到master中。再重新启动master和slave。这种方式最简单，效率也不错，但是只能有两台做集群，只能fail-over一次，而且需要停机回复master-slave结构。</p>
<h4>2.2.2 JDBC master-slave</h4>
<p>这种方式不需要特殊的配置，只要让所有的节点都把数据存储到同一个数据库中。先拿到数据库表的锁的节点成为master，一旦它失效了，其它的节点获得锁，就可以成为master。因为数据通过数据库共享，放在一个地方，不需要停机恢复master-slave。这种方式，需要额外的数据库服务器，如果数据库失效了，那么就全失效了，而且速度不是很快。我们在用mysql测试时，并没有成功，master失效后，其他的节点始终没有升级成slave，可能是数据库配置的问题。</p>
<h4>2.2.3 Share file master-slave</h4>
<p>这种方式类似于前者，也不需要特别的配置，只是通过共享文件系统来共享数据，靠文件锁实现只有一台成为master。共享文件系统的方式有很多，我们测试了nfs v4 (v3有bug，不行)， 最终在稳定性，效率等方面不是很满意，可能是通过网络太慢了。</p>
<p>测试过众多master-slave模式后发现，pure方式管理起来麻烦，jdbc方式成本高，效率低，share file方式需要高性能的共享文件，都有缺点。鉴于单台activeMQ很可靠，而我们的基础平台组愿意用硬件备份，最终还是决定不用master-slave了，也不用broker cluster，就用单台，通过硬件冗余保证数据不会丢失，并找另外一台刀片机做冷备，在主服务器失效时顶替。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/207/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>如何保证jms消息的顺序性</title>
		<link>http://www.sulong.info/archives/183</link>
		<comments>http://www.sulong.info/archives/183#comments</comments>
		<pubDate>Wed, 03 Jun 2009 03:39:58 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[jms]]></category>
		<category><![CDATA[思考]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=183</guid>
		<description><![CDATA[JMS提供的queue和topic两种工作方式，其中queue能保证消息在传输中的顺序性，这是队列先入先出(first in first out)的特性。JMS本身不能保证多个队列里的消息的顺序性，比如 先放入queue1的消息m1，并不一定总是比后放入queue2的消息m2，先到达同样的目的地。 并发地发送和接收消息不能保证消息按正确顺序进入队列和被消费。比如，有两个线程分别发送创建订单和支付订单消息，由于线程运行的不确定性，即使我们按顺序先开始发送创建订单的线程，后开始支付订单的线程，如果两个线程开始时间间隔不够长，还是有可能后开始的线程先发送掉消息。同样的情况发生在并发的接收处理消息时。 那么如何保证消息的顺序性呢？ 一种方案是，乱序接收，顺序处理。也就是说，消息在发送，传输和接收过程中可能是乱序的，但消费者在接收到消息之后，并不立即处理，而是先将消息排序，然后在处理。JMS消息头部的 JMSCorrelationID可以帮助我们完成这个工作。JMSCorrelationID存放了另一个消息的id。消息的发送者，如果要保证消息的顺序性，要将后发送的消息的JMSCorrelationID设置成前一个消息的id。消费者接收消息后，如果发现其头部有JMSCorrelationID，则查看该消息是否已被处理过，如果没有，则等待该消息，至到该消息被处理后，才处理这个消息。这一工作需要发送者和接收者都记住已经发送和接收过的消息，以便于给后来的消息参考。 另一种方案是，顺序发送，顺序传输，顺序接收，顺序处理。其中传输可以由queue来保证，但是发送接收和处理则需要应用程序来控制。简单的说，直到前一个消息发送成功，才能发送后一个消息，同样的，直到前一个消息被接受和处理结束，才能接收和处理后一个消息。这样的做法无疑会降低并发带来的好处。 以上所说的方案，是用来严格控制消息的顺序性的，然而，如果消息的发送的间隔时间足够长，不需要做过多控制，也可以控制消息的顺序性。假设，一个消息正常情况下，由发送，传输，接收到处理成功，最大时间耗费是2秒，那么只要我们保证消息发送的时间隔达不低于2秒，那么这两个消息就可以被正确的处理。这一条件咋听起来很苛刻，但事实上大部分的消息都满足了。比如，同一个订单的创建，和请求支付，最快也要数秒的时间，而退款的开始和结束，可能要数天。在典型的web应用中，操作人员不可能那么快的点击系统，而系统也不可能那么快的响应。进一步的，如果两个需要顺序处理的业务事件可能在极端的时间里连续发生，我们只要在程序上控制，人为将间隔拉开，就可以保证顺序性。 在系统的各各环节控制消息的顺序，代价高昂，而带来的好处却只是针对那极少数极端情况；通过业务或程序的方式，保证消息的有效时间间隔，代价较小，也能有效保证顺序。 如果系统中有很多的间隔极端，又需要保证顺序的消息，那你就要考虑是否将这两个消息合并成一个，或则不该采用jms了。]]></description>
			<content:encoded><![CDATA[<p>JMS提供的queue和topic两种工作方式，其中queue能保证消息在传输中的顺序性，这是队列先入先出(first in first out)的特性。JMS本身不能保证多个队列里的消息的顺序性，比如 先放入queue1的消息m1，并不一定总是比后放入queue2的消息m2，先到达同样的目的地。</p>
<p>并发地发送和接收消息不能保证消息按正确顺序进入队列和被消费。比如，有两个线程分别发送创建订单和支付订单消息，由于线程运行的不确定性，即使我们按顺序先开始发送创建订单的线程，后开始支付订单的线程，如果两个线程开始时间间隔不够长，还是有可能后开始的线程先发送掉消息。同样的情况发生在并发的接收处理消息时。</p>
<p>那么如何保证消息的顺序性呢？</p>
<p>一种方案是，乱序接收，顺序处理。也就是说，消息在发送，传输和接收过程中可能是乱序的，但消费者在接收到消息之后，并不立即处理，而是先将消息排序，然后在处理。JMS消息头部的 JMSCorrelationID可以帮助我们完成这个工作。JMSCorrelationID存放了另一个消息的id。消息的发送者，如果要保证消息的顺序性，要将后发送的消息的JMSCorrelationID设置成前一个消息的id。消费者接收消息后，如果发现其头部有JMSCorrelationID，则查看该消息是否已被处理过，如果没有，则等待该消息，至到该消息被处理后，才处理这个消息。这一工作需要发送者和接收者都记住已经发送和接收过的消息，以便于给后来的消息参考。</p>
<p>另一种方案是，顺序发送，顺序传输，顺序接收，顺序处理。其中传输可以由queue来保证，但是发送接收和处理则需要应用程序来控制。简单的说，直到前一个消息发送成功，才能发送后一个消息，同样的，直到前一个消息被接受和处理结束，才能接收和处理后一个消息。这样的做法无疑会降低并发带来的好处。</p>
<p>以上所说的方案，是用来严格控制消息的顺序性的，然而，如果消息的发送的间隔时间足够长，不需要做过多控制，也可以控制消息的顺序性。假设，一个消息正常情况下，由发送，传输，接收到处理成功，最大时间耗费是2秒，那么只要我们保证消息发送的时间隔达不低于2秒，那么这两个消息就可以被正确的处理。这一条件咋听起来很苛刻，但事实上大部分的消息都满足了。比如，同一个订单的创建，和请求支付，最快也要数秒的时间，而退款的开始和结束，可能要数天。在典型的web应用中，操作人员不可能那么快的点击系统，而系统也不可能那么快的响应。进一步的，如果两个需要顺序处理的业务事件可能在极端的时间里连续发生，我们只要在程序上控制，人为将间隔拉开，就可以保证顺序性。</p>
<p>在系统的各各环节控制消息的顺序，代价高昂，而带来的好处却只是针对那极少数极端情况；通过业务或程序的方式，保证消息的有效时间间隔，代价较小，也能有效保证顺序。</p>
<p>如果系统中有很多的间隔极端，又需要保证顺序的消息，那你就要考虑是否将这两个消息合并成一个，或则不该采用jms了。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/183/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>企业应用集成&#8211;java</title>
		<link>http://www.sulong.info/archives/166</link>
		<comments>http://www.sulong.info/archives/166#comments</comments>
		<pubDate>Tue, 28 Apr 2009 07:34:24 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[程序]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[jms]]></category>
		<category><![CDATA[思考]]></category>
		<category><![CDATA[经验]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=166</guid>
		<description><![CDATA[java企业应用最终往往运行在某种应用服务器中，比如tomcat，jboss等。部署的单元是war, jar 或者 ear文件，开始的时候，我们可能会将多个应用放到一个单元里来开发管理和部署。随着应用的增多，为了能够让每个应用能够独立的运行不受干扰，也为了开发工作能很好的安排，往往会将各应用分开，于是会有多个war, jar,或ear文件。试想一下，假设你有订单系统，产品系统，客服系统，等，如果这些应用都被放在同一个部署单元里，当需要更新客服系统时，会短暂的导致订单系统不能正常工作，而这种情况往往是不能被接受的。另外，如果客服系统非常繁忙，由于部署在同一台物理服务器上，共享硬件资源，订单系统会受到干扰，而这也不是我们想要的。将单独的应用单独打包，单独部署成为必然。那么就面临着让这些应用通信，将它们集成的问题。 与java和php之间集成相比，java与java之间的集成，不仅可以使用共享数据库，soap，或基于http的简单的文档交换，还可以使用jms，rmi等多种方案。其中jms是j2ee众多的标准中最为成功的协议之一，很少有人针对它发表过不满意见。我们在工作中就采用了jms。和http相比，它有如下优势: 为java量身定做的 jms不仅可以传输普通的字符串，还可以直接传输java对象，并和java的其它服务结合起来，接口api也符合java的使用习惯。如果用http，我们还得要考虑如何把对象序列化等问题，比较麻烦。 使用长连接 http主要用在客户端和服务器交互上，为了能让服务器支持大量的客户端，http往往都以一种无状态和短连接的方式工作。而jms主要用在java应用之间的交互，不需要支持那么多的客户端，用长连接更加适合。典型的http服务器，可能同时要给数千数万人提供服务，如果服务器和每个客户端保持一个连接，那对服务器来说，显然是一个非常大的负担。所以，通常客户端和http的一次交互完成后，连接就断开，而下次访问时，还得要重新建立连接。jms服务器面对的客户端一般只有几个，至多几十个，和每个客户端保持连接的开销是可以接受的。典型的企业可能有如下系统：订单系统，产品系统，结算系统，等等，这些系统，每个都和集中的jms服务器保持一个连接，总连接数也是很少的，所以可以保持长连接。这客户端和jms服务器通信的时候，不必每次都建立连接，减少了网络操作，提升了性能。 异步 http操作的过程是同步的，如果要使用异步的方式工作，需要程序员再做些编码工作。而jms天生就以异步的方式来工作的，不必做过多的编码。消息的生产者一旦把消息发送出去，就可以立刻返回不必等待消息的消费结果，后续的消息消费可以自动的异步执行。将不必要立刻执行的动作异步执行，可以大大降低系统的响应时间。 可靠的消息传递 在使用http通信的过程中，如果发生了网络异常，是否要做重发，以及如何重发，会是一件很痛苦的事情。jms提供了persitent的传递模式，在这种模式时，客户端代理在发送消息之前，会先把消息持久，如果发生网络异常，客户端代理会自动处理重发，而不需要应用程序关心。jms消息的唯一编号，可以有效的阻止一个消息被重复处理的问题。 在java应用集成时，jms比http更适合。成熟的jms服务器软件很多，除了ibm的mq，jboss mq, apache activemq 都是很不错的选择。]]></description>
			<content:encoded><![CDATA[<p>java企业应用最终往往运行在某种应用服务器中，比如tomcat，jboss等。部署的单元是war, jar 或者 ear文件，开始的时候，我们可能会将多个应用放到一个单元里来开发管理和部署。随着应用的增多，为了能够让每个应用能够独立的运行不受干扰，也为了开发工作能很好的安排，往往会将各应用分开，于是会有多个war, jar,或ear文件。试想一下，假设你有订单系统，产品系统，客服系统，等，如果这些应用都被放在同一个部署单元里，当需要更新客服系统时，会短暂的导致订单系统不能正常工作，而这种情况往往是不能被接受的。另外，如果客服系统非常繁忙，由于部署在同一台物理服务器上，共享硬件资源，订单系统会受到干扰，而这也不是我们想要的。将单独的应用单独打包，单独部署成为必然。那么就面临着让这些应用通信，将它们集成的问题。<br />
<br/><br />
与java和php之间集成相比，java与java之间的集成，不仅可以使用共享数据库，soap，或基于http的简单的文档交换，还可以使用jms，rmi等多种方案。其中jms是j2ee众多的标准中最为成功的协议之一，很少有人针对它发表过不满意见。我们在工作中就采用了jms。和http相比，它有如下优势:</p>
<h3>为java量身定做的</h3>
<p>jms不仅可以传输普通的字符串，还可以直接传输java对象，并和java的其它服务结合起来，接口api也符合java的使用习惯。如果用http，我们还得要考虑如何把对象序列化等问题，比较麻烦。</p>
<h3>使用长连接</h3>
<p>http主要用在客户端和服务器交互上，为了能让服务器支持大量的客户端，http往往都以一种无状态和短连接的方式工作。而jms主要用在java应用之间的交互，不需要支持那么多的客户端，用长连接更加适合。典型的http服务器，可能同时要给数千数万人提供服务，如果服务器和每个客户端保持一个连接，那对服务器来说，显然是一个非常大的负担。所以，通常客户端和http的一次交互完成后，连接就断开，而下次访问时，还得要重新建立连接。jms服务器面对的客户端一般只有几个，至多几十个，和每个客户端保持连接的开销是可以接受的。典型的企业可能有如下系统：订单系统，产品系统，结算系统，等等，这些系统，每个都和集中的jms服务器保持一个连接，总连接数也是很少的，所以可以保持长连接。这客户端和jms服务器通信的时候，不必每次都建立连接，减少了网络操作，提升了性能。</p>
<h3>异步</h3>
<p>http操作的过程是同步的，如果要使用异步的方式工作，需要程序员再做些编码工作。而jms天生就以异步的方式来工作的，不必做过多的编码。消息的生产者一旦把消息发送出去，就可以立刻返回不必等待消息的消费结果，后续的消息消费可以自动的异步执行。将不必要立刻执行的动作异步执行，可以大大降低系统的响应时间。</p>
<h3>可靠的消息传递</h3>
<p>在使用http通信的过程中，如果发生了网络异常，是否要做重发，以及如何重发，会是一件很痛苦的事情。jms提供了persitent的传递模式，在这种模式时，客户端代理在发送消息之前，会先把消息持久，如果发生网络异常，客户端代理会自动处理重发，而不需要应用程序关心。jms消息的唯一编号，可以有效的阻止一个消息被重复处理的问题。<br />
<br/></p>
<p>在java应用集成时，jms比http更适合。成熟的jms服务器软件很多，除了ibm的mq，jboss mq, apache activemq 都是很不错的选择。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/166/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>如何让jboss下的消息驱动bean消费远程JMS消息</title>
		<link>http://www.sulong.info/archives/130</link>
		<comments>http://www.sulong.info/archives/130#comments</comments>
		<pubDate>Wed, 10 Dec 2008 11:44:58 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[技巧]]></category>
		<category><![CDATA[程序]]></category>
		<category><![CDATA[jboss]]></category>
		<category><![CDATA[jms]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=130</guid>
		<description><![CDATA[用消息驱动bean来处理本地的JMS消息太容易不过了，但是如何处理远程的消息呢？翻遍了Java EE手册和API也找不到。原来各种应用服务器都有各自的实现。那么如何让jboss下的消息驱动bean消费远程JMS消息呢？把下面的代码复制到一个文件里，并重名为以-service.xml结尾的文件，放到jboss的deploy目录，就可以在本地得到一个从远程获取消息的JMS provider。 &#160; &#160; &#60;mbean code=&#34;org.jboss.jms.jndi.JMSProviderLoader&#34; name=&#34;jboss.mq:service=JMSProviderLoader,name=RemoteJMSProvider,server=remotehost&#34;&#62; &#160; &#160; &#160; &#160; &#60;attribute name=&#34;ProviderName&#34;&#62;RemoteJMSProvider&#60;/attribute&#62; &#160; &#160; &#160; &#160; &#60;attribute name=&#34;ProviderAdapterClass&#34;&#62;org.jboss.jms.jndi.JNDIProviderAdapter&#60;/attribute&#62; &#160; &#160; &#160; &#160; &#60;!-- The connection factory --&#62; &#160; &#160; &#160; &#160; &#60;attribute name=&#34;FactoryRef&#34;&#62;UIL2XAConnectionFactory&#60;/attribute&#62; &#160; &#160; &#160; &#160; &#60;!-- The queue connection factory --&#62; &#160; &#160; &#160; &#160; &#60;attribute name=&#34;QueueFactoryRef&#34;&#62;UIL2XAConnectionFactory&#60;/attribute&#62; &#160; &#160; &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>用消息驱动bean来处理本地的JMS消息太容易不过了，但是如何处理远程的消息呢？翻遍了Java EE手册和API也找不到。原来各种应用服务器都有各自的实现。那么如何让jboss下的消息驱动bean消费远程JMS消息呢？把下面的代码复制到一个文件里，并重名为以-service.xml结尾的文件，放到jboss的deploy目录，就可以在本地得到一个从远程获取消息的JMS provider。<br/></p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;mbean</span> <span style="color: #000066;">code</span>=<span style="color: #ff0000;">&quot;org.jboss.jms.jndi.JMSProviderLoader&quot;</span> </span><br />
<span style="color: #009900;"><span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;jboss.mq:service=JMSProviderLoader,name=RemoteJMSProvider,server=remotehost&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;ProviderName&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>RemoteJMSProvider<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;ProviderAdapterClass&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>org.jboss.jms.jndi.JNDIProviderAdapter<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- The connection factory --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;FactoryRef&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>UIL2XAConnectionFactory<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- The queue connection factory --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;QueueFactoryRef&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>UIL2XAConnectionFactory<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- The topic factory --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;TopicFactoryRef&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>UIL2XAConnectionFactory<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Connect to JNDI on the host &quot;the-remote-host-name&quot; port 1099--&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;Properties&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; java.naming.factory.url.pkgs=org.jnp.interfaces<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; java.naming.provider.url=the-remote-host-name:1099<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/mbean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p><br/><br />
注意，你要把上面的 the-remote-host-name 改成你的。部署完成后，确认在jboss的JndiViewer里能不能看到 java:/RemoteJMSProvider 。然后再MDB类上加上：<br/></p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; @MessageDriven<span style="color: #009900;">&#40;</span>activateConfig <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; @ActivationConfigProperty<span style="color: #009900;">&#40;</span>propertyName<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;destinationType&quot;</span>, propertyValue<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;javax.jms.Queue&quot;</span><span style="color: #009900;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; @ActivationConfigProperty<span style="color: #009900;">&#40;</span>propertyName<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;destination&quot;</span>, propertyValue<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;queue/testQueue&quot;</span><span style="color: #009900;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; @ActivationConfigProperty<span style="color: #009900;">&#40;</span>propertyName<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;providerAdapterJNDI&quot;</span>, propertyValue<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;java:/RemoteJMSProvider&quot;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MDB <span style="color: #000000; font-weight: bold;">implements</span> MessageListener <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span></div></div>
<p><br/><br />
providerAdapterJNDI属性使这个MDB从刚才部署好的JMS provider那里读取消息。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/130/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
