如何用c/c++来实现jmsjms2.0规范中文版 pdf

为什么我希望用C而不是C++来实现ZeroMQ
开始前我要先做个澄清:这篇文章同Linus Torvalds这种死忠C程序员吐槽C++的观点是不同的。在我的整个职业生涯里我都在使用C++,而且现在C++依然是我做大多数项目时的首选编程语言。自然的,当我从2007年开始做时,我选择用C++来实现。主要的原因有以下几点:
1. 包含数据结构和算法的库(STL)已经成为这个语言的一部分了。如果用C,我将要么依赖第三方库要么不得不自己手动写一些自1970年来就早已存在的基础算法。
2. C++语言本身在编码风格的一致性上起到了一些强制作用。比如,有了隐式的this指针参数,这就不允许通过各种不同的方式将指向对象的指针做转换,而那种做法在C项目中常常见到(通过各种类型转换)。同样的还有可以显式的将成员变量定义为私有的,以及许多其他的语言特性。
3. 这个观点基本上是前一个的子集,但值得我在这里显式的指出:用C语言实现虚函数机制比较复杂,而且对于每个类来说会有些许的不同,这使得对代码的理解和维护都会成为痛苦之源。
4. 最后一点是:人人都喜欢析构函数,它能在变量离开其作用域时自动得到调用。
如今,5年过去了,我想公开承认:用C++作为ZeroMQ的开发语言是一个糟糕的选择,后面我将一一解释为什么我会这么认为。
首先,很重要的一点是ZeroMQ是需要长期连续不停运行的一个网络库。它应该永远不会出错,而且永远不能出现未定义的行为。因此,错误处理对于ZeroMQ来说至关重要,错误处理必须是非常明确的而且对错误应该是零容忍的。
C++的异常处理机制却无法满足这个要求。C++的异常机制对于确保程序不会失败是非常有效的——只要将主函数包装在try/catch块中,然后你就可以在一个单独的位置处理所有的错误。然而,当你的目标是确保没有未定义行为发生时,噩梦就产生了。C++中引发异常和处理异常是松耦合的,这使得在C++中避免错误是十分容易的,但却使得保证程序永远不会出现未定义行为变得基本不可能。
在C语言中,引发错误和处理错误的部分是紧耦合的,它们在源代码中处于同一个位置。这使得我们在错误发生时能很容易理解到底发生了什么:
int rc = fx ();
if (rc != 0)
handle_error();
在C++中,你只是抛出一个异常,到底发生了什么并不能马上得知。
int rc = fx();
if (rc != 0)
throw std::exception();
这里的问题就在于你对于谁处理这个异常,以及在哪里处理这个异常是不得而知的。如果你把异常处理代码也放在同一个函数中,这么做或多或少还有些明智,尽管这么做会牺牲一点可读性。
int rc = fx();
if (rc != 0)
throw std::exception(“Error!”);
catch (std::exception &e) {
handle_exception();
但是,考虑一下,如果同一个函数中抛出了两个异常时会发生什么?
class exception1 {};
class exception2 {};
if (condition1)
throw my_exception1();
if (condition2)
throw my_exception2();
catch (my_exception1 &e) {
handle_exception1();
catch (my_exception2 &e) {
handle_exception2();
对比一下相同的C代码:
if (condition1)
handle_exception1();
if (condition2)
handle_exception2();
C代码的可读性明显高的多,而且还有一个附加的优势——编译器会为此产生更高效的代码。这还没完呢。再考虑一下这种情况:异常并不是由所抛出异常的函数来处理。在这种情况下,异常处理可能发生在任何地方,这取决于这个函数是在哪调用的。虽然乍一看我们可以在不同的上下文中处理不同的异常,这似乎很有用,但很快就会变成一场噩梦。
当你在解决bug的时候,你会发现几乎同样的错误处理代码在许多地方都出现过。在代码中增加一个新的函数调用可能会引入新的麻烦,不同类型的异常都会涌到调用函数这里,而调用函数本身并没有适当进行的处理,这意味着什么?新的bug。
如果你依然坚持要杜绝“未定义的行为”,你不得不引入新的异常类型来区分不同的错误模式。然而,增加一个新的异常类型意味着它会涌现在各个不同的地方,那么就需要在所有这些地方都增加一些处理代码,否则你又会出现“未定义的行为”。到这里你可能会尖叫:这特么算什么异常规范哪!
好吧,问题就在于异常规范只是以一种更加系统化的方式,以按照指数规模增长的异常处理代码来处理问题的工具,它并没有解决问题本身。甚至可以说现在情况更加糟糕了,因为你不得不去写新的异常类型,新的异常处理代码,以及新的异常规范。
通过上面我描述的问题,我决定使用去掉异常处理机制的C++。这正是ZeroMQ以及今天的样子。但是,很不幸,问题到这并没有结束…
考虑一下当一个对象初始化失败的情况。构造函数没有返回值,因此出错时只能通过抛出异常来通知出现了错误。可是我已经决定不使用异常了,那么我不得不这样做:
int init();
当你创建这个类的实例时,构造函数被调用(不允许失败),然后你显式的去调用init来初始化(init可能会失败)对象。相比于C语言中的做法,这就显得过于复杂了。
struct foo
int foo_init(struct foo *self);
但是以上的例子中,C++版本真正邪恶的地方在于:如果有程序员往构造函数中加入了一些真正的代码,而不是将构造函数留空时会发生什么?如果有人真的这么做了,那么就会出现一个新的特殊的对象状态——“半初始化状态”。这种状态是指对象已经完成了构造(构造函数调用完成,且没有失败),但init函数还没有被调用。我们的对象需要修改(特别是析构函数),这里应该以一种方式妥善的处理这种新的状态,这就意味着又要为每一个方法增加新的条件。
看到这里你可能会说:这就是你人为的限制使用异常处理所带来的后果啊!如果在构造函数中抛出异常,C++运行时库会负责清理适当的对象,那这里根本就没有什么“半初始化状态”了!很好,你说的很对,但这根本无关紧要。如果你使用异常,你就不得不处理所有那些与异常相关的复杂情况(我前面已经描述过了)。而这对于一个面对错误时需要非常健壮的基础组件来说并不是一个合理的选择。
此外,就算初始化不是问题,那析构的时候绝对会有问题。你不能在析构函数中抛出异常,这可不是什么人为的限制,而是如果析构函数在堆栈辗转开解()的过程中刚好抛出一个异常的话,那整个进程都会因此而崩溃。因此,如果析构过程可能失败的话,你需要两个单独的函数来搞定它:
int term();
现在,我们又回到了前面初始化的问题上来了:这里出现了一个新的“半终止状态”需要我们去处理,又需要为成员函数增加新的条件了…
foo () : state (semi_initialised)
int init ()
if (state != semi_initialised)
handle_state_error ();
int term ()
if (state != initialised)
handle_state_error ();
state = semi_
if (state != semi_terminated)
handle_state_error ();
int bar ()
if (state != initialised)
handle_state_error ();
将上面的例子与同样的C语言实现做下对比。C语言版本中只有两个状态。未初始化状态:整个结构体可以包含随机的数据;以及初始化状态:此时对象完全正常,可以投入使用。因此,根本没必要在对象中加入一个状态机。
struct foo
int foo_init ()
int foo_term ()
int foo_bar ()
现在,考虑一下当你把继承机制再加到这趟浑水中时会发生什么。C++允许把对基类的初始化作为派生类构造函数的一部分。抛出异常时将析构掉对象已经成功初始化的那部分。
class foo: public bar
foo ():bar () {}
但是,一旦你引入单独的init函数,那么对象的状态数量就会增加。除了“未初始化”、“半初始化”、“初始化”、“半终止”状态外,你还会遇到这些状态的各种组合!!打个比方,你可以想象一下一个完全初始化的基类和一个半初始化状态的派生类。
这种对象根本不可能保证有确定的行为,因为有太多状态的组合了。鉴于导致这类失败的原因往往非常罕见,于是大部分相关的代码很可能未经过测试就进入了产品。
总结以上,我相信这种“定义完全的行为”(fully-defined behaviour)打破了面向对象编程的模型。这不是专门针对C++的,而是适用于任何一种带有构造函数和析构函数机制的面向对象编程语言。
因此,似乎面向对象编程语言更适合于当快速开发的需求比杜绝一切未定义行为要更为重要的场景中。这里并没有银弹,系统级编程将不得不依赖于C语言。
最后顺带提一下,我已经开始将Crossroads I/O(ZeroMQ的fork,我目前正在做的)由C++改写为C版本。代码看起来棒极了!
译注:这篇新出炉的文章引发了大量的回复,有觉得作者说的很对的,也有人认为这根本不是C++的问题,而是作者错误的使用了异常,以及设计上的失误,也有读者提到了Go语言可能是种更好的选择。好在作者也都能积极的响应回复,于是产生了不少精彩的技术讨论。建议中国的程序员们也可以看看国外的开发者们对于这种“吐槽”类文章的态度以及他们讨论问题的方式。
英文原文: 编译:在线—
C也抛异常,不是有人骂java抛异常这东西吗。
--- 共有 1 条评论 ---
我就是,Java那异常处理的方式简直能让人气死,主流语言三大恶疾:C++的模板、Java的异常、C的指针错误
异常处理被滥用在java中也是一个严重的问题
--- 共有 3 条评论 ---
更严重的问题是James Gosling这偏执狂异想天开引入CheckedException,还有一堆抖M乐在其中。
使用好异常真的是一种艺术啊。
JDK中也存在很多异常处理,开元框架中同样存在N多异常处理,不知道你说的滥用具体是怎么用,但这不是个人问题,同样也不是JAVA应该重点考虑的问题。
引用来自“崔钢”的答案异常处理被滥用在java中也是一个严重的问题那是因为java开发人员太多太多 导致平均水平被拉低太多太多
--- 共有 1 条评论 ---
因果好像倒了。
自已不会好好用,还说人家这个不好,那个不好.
--- 共有 11 条评论 ---
: 国内牛人是有,但是少得可怜。云风要牛也反正不是牛在C++。
: 《C++现代泛型编程思想》《
Imperfect C++》《C++模板》三本书,如果仁兄没有拜读过,建议去看看,或许能否然你对C++模板有更深入的了解。当然这几本书是基于C++11之前的,某些功能在C++11已经实现或许较容易实现。这三本书,个人愚钝,基本上是拜读了五六遍以上,仍然有很多地方不明白。。
: 呵呵,我没看过那个,不好发言。但正因为用过才有发言权,不是吗?用过了才知道原来用那个东西是非常不好的,搞得代码很混乱,有些时候是为了用而用,这才是问题所在。
: 你可知道云风游戏引擎里面的很多高级东西,是使用模板实现的??
其实不是语言的问题,主要还是被滥用了,很多人非要一个简单程序里面用上模板啥的一大堆,显得自己很高级,就跟JAVA web的一样,简单的增删改查,非要上SSH,这说到底只是水平的问题。
但楼主说的不大赞同,C++是一个有太多特性的语言,但问题是太多的东西是没什么用,但又不像语法糖可以大量节省编码生命的,而且它又好像故意引导别人去用那些所谓高级功能,所以才会有太多人喷。
C++提供东西的越多, 像异常这玩意, 个人觉得要么不要用, 要么就得提供两套, 一套返回error_code, 一套throw error_code, 正如boost里的一些库那样设计, 如:
int read(stream &s, error_code &err);
int read(stream &s); // throw error_code.
个人认为, 一个通用的C++库, API就应该被设计成这样.
--- 共有 1 条评论 ---
very agree.
ZMQ本身定位于网络通信基础架构,替代底层的socket接口,据说想变成linux的标配。
如果我理解的这个定位不错的话,确实是该用C来实现。
用什么语言除了性能外,其他原因全依赖周围团队成员的开发习惯, C++,C,JAVA,各有优缺点,如果ZMQ不加入linux标配的话,用C++实现有什么错。上面的几个例子根本不能说明问题。
没有看完,不过我觉得如果认为C++异常不好用,你也可以不用,C++没有强迫你一定要使用异常。
--- 共有 1 条评论 ---
对头,C++完全可以写出C风格的C++,我个人习惯,从不用C++异常
都没看文章就吐槽的人最可恶。。作者的意思都没看明白就急于表达自己的观点。。。
ZeroMQ几乎是用C来做的(应该没有用到任何标准C之外的库,比如STL),但是表现出来的是CXX,在socket类型的抽象上使用了些C++的类别抽象优势。我个人赞成这种做法的,结合C和部分C++的优势,不过度使用面向对象的CXX,不能弄明白直接了然的C++特性一律谨慎使用
--- 共有 1 条评论 ---
这样半吊子毛用,远不如纯C干净。2006年4月 Oracle大版内专家分月排行榜第三
2008年8月 Linux/Unix社区大版内专家分月排行榜第一2008年7月 Linux/Unix社区大版内专家分月排行榜第一2006年7月 Linux/Unix社区大版内专家分月排行榜第一2006年5月 Linux/Unix社区大版内专家分月排行榜第一2006年4月 Linux/Unix社区大版内专家分月排行榜第一2006年3月 Linux/Unix社区大版内专家分月排行榜第一2006年2月 Linux/Unix社区大版内专家分月排行榜第一2006年1月 Linux/Unix社区大版内专家分月排行榜第一2004年3月 Linux/Unix社区大版内专家分月排行榜第一2004年2月 Linux/Unix社区大版内专家分月排行榜第一2004年1月 Linux/Unix社区大版内专家分月排行榜第一2003年12月 Linux/Unix社区大版内专家分月排行榜第一2003年11月 Linux/Unix社区大版内专家分月排行榜第一2003年10月 Linux/Unix社区大版内专家分月排行榜第一2003年9月 Linux/Unix社区大版内专家分月排行榜第一2003年8月 Linux/Unix社区大版内专家分月排行榜第一
2003年11月 C/C++大版内专家分月排行榜第二2006年6月 Linux/Unix社区大版内专家分月排行榜第二2003年7月 Linux/Unix社区大版内专家分月排行榜第二
本帖子已过去太久远了,不再提供回复功能。深入掌握JMS(十)JMSCorrelationID和Selector_C++,C语言_ThinkSAAS
深入掌握JMS(十)JMSCorrelationID和Selector
深入掌握JMS(十)JMSCorrelationID和Selector
内容来源: 网络
前面讲过JMSCorrelationID主要是用来关联多个Message,例如需
要回复一个消息的时候,通常把回复的消息的
JMSCorrelationID设置为原来消息的ID。在下面这个例子中,创建了三个消息生产者A,B,C和三个消息消费者A,B,C。生产者A给消费
者A发送一个消息,同时需要消费者A给它回复一个消息。B、C与A类似。
简图如下:
-----发送----〉消费者A
-----回复------〉生产者A
-----发送----〉消费者B
-----回复------〉生产者B
-----发送----〉消费者C
-----回复------〉生产者C
需要注意的是,所有的发送和回复都使用同一个Queue,通过Selector区分。
import javax.jms.*;
import org.apache.activemq.ActiveMQConnectionF
import org.mand.ActiveMQQ
public class JMSCorrelationIDTest {
public JMSCorrelationIDTest() throws JMSException{
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost");
Connection connection = factory.createConnection();
connection.start();
queue = new ActiveMQQueue("testQueue");
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
setupConsumer("ConsumerA");
setupConsumer("ConsumerB");
setupConsumer("ConsumerC");
setupProducer("ProducerA","ConsumerA");
setupProducer("ProducerB","ConsumerB");
setupProducer("ProducerC","ConsumerC");
private void setupConsumer(final String name) throws JMSException {
//创建一个消费者,它只接受属于它自己的消息
MessageConsumer consumer = session.createConsumer(queue,"receiver='"+ name +"'");
consumer.setMessageListener(new MessageListener(){
public void onMessage(Message m) {
MessageProducer producer = session.createProducer(queue);
System.out.println(name +"get:"+ ((TextMessage)m).getText());
//回复一个消息
Message replyMessage = session.createTextMessage("Reply from"+ name);
//设置JMSCorrelationID为刚才收到的消息的ID
replyMessage.setJMSCorrelationID(m.getJMSMessageID());
producer.send(replyMessage);
} catch (JMSException e) { }
private void setupProducer(final String name, String consumerName) throws JMSException {
MessageProducer producer = session.createProducer(queue);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
//创建一个消息,并设置一个属性receiver,为消费者的名字。
Message message = session.createTextMessage("Message from"+ name);
message.setStringProperty("receiver", consumerName);
producer.send(message);
//等待回复的消息
MessageConsumer replyConsumer = session.createConsumer(queue,"JMSCorrelationID='"+ message.getJMSMessageID() +"'");
replyConsumer.setMessageListener(new MessageListener(){
public void onMessage(Message m) {
System.out.println(name +"get reply:"+ ((TextMessage)m).getText());
} catch (JMSException e) { }
public static void main(String[] args) throws Exception {
new JMSCorrelationIDTest ();
运行结果为:
ConsumerA get:Message from ProducerA
ProducerA get reply:Reply from ConsumerA
ConsumerB get:Message from ProducerB
ProducerB get reply:Reply from ConsumerB
ConsumerC get:Message from ProducerC
ProducerC get reply:Reply from ConsumerC
PHP开发框架
开发工具/编程工具
服务器环境
ThinkSAAS商业授权:
ThinkSAAS为用户提供有偿个性定制开发服务
ThinkSAAS将为商业授权用户提供二次开发指导和技术支持
让ThinkSAAS更好,把建议拿来。
开发客服微信如何在同一个程序中混合使用C++和C - 推酷
如何在同一个程序中混合使用C++和C
如何在同一个程序中混合使用C++和C
名变换,就是C++编译器给程序的每个函数换一个独一无二的名字。
由函数名和参数组合生成一个新的名字,这样为了支持函数重载
在C语言中,这样的做法是不必要的,因为它没有重载函数。
这样就存在一个问题:就是当你在C++环境中调用C函数库中的函数时,比如一个drawLine(int x,int y)。经过C++编译器后在obj中的函数名称可能是drawLine_int_int,这样当你试图将obj文件链接为程序时,将得到一个错误。因为链接程序无法在C函数库中找到drawLine_int_int。
要解决这个问题,你需要一种方法来告诉C++编译器不要在这个函数上进行名变换。你不期望对用其它语言写的函数进行名变换,如C、汇编、Fortran、LISP、Forth或其它。
总之,如果你调用一个名字为drawLine的C函数,它实际上就叫drawLine,你的obj文件应该包含这样的一个引用,而不是引用进行了名变换的版本。
extern &C&
void drawLine(int x1, int y1, int x2, int y2);
不要以为有一个extern 'C',那么就应该同样有一个extern 'Pascal'什么的,这里extern ‘C’应看做是声明这个函数应该被当做好像是C写的一样来进行调用,要禁止名称变换。
你甚至可以在C++函数上申明extern 'C'。这在你用C++写一个库给使用其它语言的客户使用时有用。通过禁止这些C++函数的名变换,你的客户可以使用你选择的自然而直观的名字,而不用使用你的编译生成的变换后的名字。
如果你有一堆函数不想进行名变化,那么你可以简单的通过加一对大括号来实现
extern &C&
// disable name mangling for
// all the following functions
void drawLine(int x1, int y1, int x2, int y2);
void twiddleBits(unsigned char bits);
void simulate(int iterations);
通过定义一个宏,我们可以轻松的控制是否需要添加extern &C&。比如程序放在C++编译器下编译时我们需要添加extern &C&,而在C编译器下编译时就不需要了。
下面的功能就是,当我们定义了_cplusplus这个宏的话,说明是在C++环境下,那么条件编译指令将被执行,也就是定义extern &C&,否则是在C环境下,不会定义。
#ifdef __cplusplus
extern &C& {
void drawLine(int x1, int y1, int x2, int y2);
void twiddleBits(unsigned char bits);
void simulate(int iterations);
#ifdef __cplusplus
这里我们还需要知道一点是,不同的编译器可能使用了不同的名称变换规则。所以当你链接由不同的编译器得来的obj的时候,如果出现链接错误,那就不要感到吃惊了。
2.动态内存分配
严格遵守:C++部分使用new和delete,C部分使用malloc和free。
new分配的内存使用delete释放,malloc分配的内存用free释放。
3.数据结构的兼容性
如果在C++和C之间传递数据,我们不能期望C的函数能够了解或支持C++的特性,也就是说它们的交互必须限定在C可支持的概念上。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致JMS&provider&&&&An&implementation&of&the&JMS&interface&for&a&Message&Oriented&Middleware&(MOM).&Providers&are&implemented&as&either&a&Java&JMS&implementation&or&an&adapter&to&a&non-Java&MOM.JMS&client&&&&An&application&or&process&that&produces&and/or&receives&messages.JMS&producer/publisher&&&&A&JMS&client&that&creates&and&sends&messages.JMS&consumer/subscriber&&&&A&JMS&client&that&receives&messages.JMS&message&&&&An&object&that&contains&the&data&being&transferred&between&JMS&clients.JMS&queue&&&&A&staging&area&that&contains&messages&that&have&been&sent&and&are&waiting&to&be&read.&Note&that,&contrary&to&what&the&name&queue&suggests,&messages&don't&have&to&be&delivered&in&the&order&sent.&A&JMS&queue&only&guarantees&that&each&message&is&processed&only&once.JMS&topic&&&&A&distribution&mechanism&for&publishing&messages&that&are&delivered&to&multiple&subscribers.&在JMS中,支持两种消息模型,点对点(Point-to-point)和发布-订阅(Publish and subscribe),这两种模式分别对应于JMS中的两种消息目标(Message Destination):队列及主题。在点对点模型中,每个消息都有一个发送者和一个接收者,消息中介(broker)收到发送者的消息,会将消息放入队列中,而接收者请求并接收队列中的一条消息后,这条消息就会从队列中删除。消息队列中的每条消息只能投递给一个接收者,但并不意味着只能使用一个接收者从队列中取消息,根据业务需要,可以使用多个接收者同时从队列中请求消息,分担处理压力。但是需要注意的是,单个接收者收到的消息是按照发送顺序的,多个接收者因为多线程的关系,并不能保证收到的消息一定是原序的。在发布-订阅模式中,消息会发送给一个主题,但是与点对点模式不同的是消息不再只被投递给一个接收者,而是所有此主题的订阅者都会收到该消息。JMS消息类型在JMS1.1规范中,定义了五种消息类型,分别为:1.StreamMessage :消息体是 Java 流,写入和读出都是顺序的2.MapMessage :消息体包含 key-value 对, key 为 String , value 为基本类型,可以通过迭代器访问3.TextMessage :消息体是 String4.ObjectMessage :消息体是可序列化的 Java 对象5.BytesMessage :消息体是字节数组可以通过 message.clearBody() 来清除消息体;但在消费端,消息体是只读的,针对消息的写操作都会抛出 MessageNotWritableException 异常JMS消息头所有消息的消息头都具体相同的字段,用于 JMS Client 以及 JMS Provider 对它们进行区别以及进行消息路由1.JMSDestination消息发送的目的地(队列或主题);创建消息时可以设置 JMSDestination ,但是在发送完成时其值会更新为发送方所指定的 JMSDestination ,也就是说发送前该字段会被忽略;当消息被消费时,该字段的值与在它被发送时被设置的值是相同的以下所有示例均基于ActiveMQSession&session&=&connection.createSession(false,&Session.AUTO_ACKNOWLEDGE);//&创建2个目的地Destination&destination&=&session.createQueue("JMS.DEMO");Destination&destination2&=&session.createQueue("JMS.DEMO2");//&创建生产者MessageProducer&publisher&=&session.createProducer(destination);//&设置传输模式publisher.setDeliveryMode(DeliveryMode.PERSISTENT);//&创建消息TextMessage&message&=&session.createTextMessage("Test&Message");//&设置消息的目的地为destination2message.setJMSDestination(destination2);//&发送消息publisher.send(message);System.out.println(message.getJMSDestination());代码中,通过 message.setJMSDestination(destination2); 设置了 message 的 JMSDestination 消息头属性值,我们再看看其输出结果queue://JMS.DEMO通过这个例子可以看出,虽然在发送前设置了消息的目的地,但是发送后消息的目的地被重置了2.JMSDeliveryMode指明消息的传输模式,有两种:DeliveryMode.PERSISTENT :保证消息仅传一次, JMS Provider 服务停止后消息不会丢失;DeliveryMode.NON_PERSISTENT :消息最多传一次,消息会因 JMS Provider 停止后丢失;同 JMSDestination 一样,在发送前设置的会被忽略看下面的例子Session&session&=&connection.createSession(false,&Session.AUTO_ACKNOWLEDGE);//&创建目的地Destination&destination&=&session.createQueue("JMS.DEMO");//&创建生产者MessageProducer&publisher&=&session.createProducer(destination);//&设置传输模式publisher.setDeliveryMode(DeliveryMode.PERSISTENT);//&发送PERSISTENT消息publisher.send(session.createTextMessage("PERSISTENT&MESSAGE"));//&设置传输模式publisher.setDeliveryMode(DeliveryMode.NON_PERSISTENT);//&发送PERSISTENT消息publisher.send(session.createTextMessage("NON_PERSISTENT&MESSAGE"));例子中分别发送了一条 PERSISTENT 的消息和一条 NON_PERSISTENT 的消息;当 Active MQ 重启后,启动消费端,收到的消息如下PERSISTENT&MESSAGE该例子说明,在 JMS Provider 重启后, NON_PERSISTENT 消息丢失了,而 PERSISTENT 消息能正常被消费者消费3.JMSMessageID由 JMS Provider 指定的消息的唯一标识符;同上面的字段一样,在发送前设置的会被忽略,在发送完成时,由 JMS Provider 重置该字段4.JMSReplyTo发送端在发送消息时,可以指定该属性(为一个 JMSDestination ),表示期望收到客户端的响应;是否响应由消费端决定如下面的例子:发送端:&Session&session&=&connection.createSession(false,&Session.AUTO_ACKNOWLEDGE);//&创建目的地Destination&destination&=&session.createQueue("JMS.DEMO");Destination&destination2&=&session.createQueue("JMS.DEMO3");//&创建生产者MessageProducer&publisher&=&session.createProducer(destination);//&设置传输模式publisher.setDeliveryMode(DeliveryMode.PERSISTENT);//&创建消息TextMessage&message&=&session.createTextMessage("Test&Message");message.setJMSReplyTo(destination2);//&发送消息publisher.send(message);接收端(可以根据情况决定是否需要回复)public&void&onMessage(Message&message)&{&&&&try&{&&&&&&&&System.out.println("Receive&message:&"&+&message);&&&&&&&&if&(message.getJMSReplyTo()&!=&null)&{&&&&&&&&&&&&session.createProducer(message.getJMSReplyTo()).send(session.createTextMessage("This&is&a&reply&to"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&+&message.getJMSReplyTo()));&&&&&&&&}&&&&}&catch&(Exception&e)&{&&&&&&&&e.printStackTrace();&&&&}}5.JMSRedelivered当消费者收到带有 JMSRedelivered 的消息头时,表明该消息在过去传输过但没有被确认JMS Provider 必须对该字段进行设置,当为 true 时即告知消费者该消息是重传的,消费者需要自行处理重复的消息6.JMSExpiration消息的过期时间,其值为当前时间加上存活时间(毫秒);当存活时间设置为 0 时,该字段的值也被设置为 0 ,表示永不过期;消费端在一般情况下都不会接收到过期的消息,但 JMS Provider 并不保证这一点;下面的例子说明了如何设置消息的过期时间Session&session&=&connection.createSession(false,&Session.AUTO_ACKNOWLEDGE);//&创建目的地Destination&destination&=&session.createQueue("JMS.DEMO");//&创建生产者MessageProducer&publisher&=&session.createProducer(destination);//&设置传输模式publisher.setDeliveryMode(DeliveryMode.PERSISTENT);//&创建消息TextMessage&message&=&session.createTextMessage("Test&Message");//&发送消息publisher.setTimeToLive(5000);publisher.send(message);7.JMSPriority消息的优先级, 0 代表最低优先级, 9 代表最高优先级;一般 0~4 为普通优先级, 5~9 为加快优先级JMS 规范里并没有要求 JMS Provider 严格按这个优先级来实现,但是尽可能实现加快优先级消息的传输在普通消息的前面同 JMSDestination 一样,该字段在发送前被忽略,在发送完成时重置消息属性除了前面提到的消息头以外, JMS 消息还提供了对“属性值对”的支持,以对消息头进行扩展;消息属性主要用于消息选择器 (message selector 详见下文 )&1.属性名属性名必须服务消息选择器的命名规则2.属性值可以是基本类型及其对象类型以及 Map 、 List 和 String下面的例子中,消息带 HashMap 的属性Session&session&=&connection.createSession(false,&Session.AUTO_ACKNOWLEDGE);//&创建目的地Destination&destination&=&session.createQueue("JMS.DEMO");//&创建生产者MessageProducer&publisher&=&session.createProducer(destination);//&设置传输模式publisher.setDeliveryMode(DeliveryMode.PERSISTENT);//&创建消息TextMessage&message&=&session.createTextMessage("Test&Message");//&发送消息message.setObjectProperty("myProp",&new&HashMap()&{&&&&{&&&&&&&&this.put("key1",&"value1");&&&&&&&&this.put("key2",&"value2");&&&&}});publisher.send(message);3.清除属性JMS 不能清除单个属性,但可以通过 Message.clearProperties() 方法清除所有消息属性JMS实现(Provider implementations)要使用JMS,必须要有相应的实现来管理session以及队列,从Java EE1.4开始,所有的Java EE应用服务器必须包含一个JMS实现。以下是一些JMS实现:& & Apache ActiveMQ& & Apache Qpid, using AMQP& & BEA Weblogic (part of the Fusion Middleware suite) and Oracle AQ from Oracle& & EMS from TIBCO& & FFMQ, GNU LGPL licensed& & JBoss Messaging and HornetQ from JBoss& & JORAM, from the OW2 Consortium& & Open Message Queue, from Sun Microsystems& & OpenJMS, from The OpenJMS Group& & RabbitMQ, using AMQP& & Solace JMS from Solace Systems& & SonicMQ from Progress Software& & StormMQ, using AMQP& & SwiftMQ& & Tervela& & Ultra Messaging from 29 West (acquired by Informatica)& & webMethods from Software AG& & WebSphere Application Server from IBM, which provides an inbuilt default messaging provider known as the Service Integration Bus (SIBus), or which can connect to WebSphere MQ as a JMS provider [5]& & WebSphere MQ (formerly MQSeries) from IBMRef from:1.http://en.wikipedia.org/wiki/Java_Message_Service2.Spring in Action3./blog/1155647
阅读排行榜
评论排行榜

我要回帖

更多关于 jms规范 的文章

 

随机推荐