1.背景本文接上一篇《Java 帝国之消息队列》自从张家村的ZhangMQ出来后,大家看到了消息队列在分布式系统中的巨大好处,纷纷开始创建自己的消息队列,各种MQ产品如雨后春笋般冒出来春雨过后,各家公司都在疯狂推销自己的宝贝。为了吸引程序员使用,八仙各渡海,各显神通,定义了各种API。由于独立开发,这些API协议多种多样,互不兼容。学习成本高,使用起来很不方便。这是帝国所不能容忍的!事实上,Java帝国非常擅长创建标准的协议和接口。前面的JDBC就是一个典型的例子(见文章《JDBC的诞生》)。制定好协议后,让各产品厂商去执行。数据库编程的统一接口。既然数据库能做到这一点,那么消息队列肯定没有问题!自从张家村研发出第一个消息队列产品,帝国就赋予了张家村制定接口标准的光荣使命。2.消息队列接口设计经验丰富的张家村老村长把任务交给了小张,告诉他我们要做的是厂商无关的标准接口,让他先调查一下流行的MQ的现状.小张先找到了大厂大名鼎鼎的MQ,在企业级市场占有很大份额,但是直接用它的JavaAPI编程可没那么容易,大家可以快速浏览一下:小张看得出来这是我的发送消息,但是MQEnvironment、openOptions、MQPutMessageOptions好像让小张很不爽,尤其是QueueManager的概念理解起来有点吃力。小张又找了一个开源的RabbitMQ,看起来清爽多了:但是queueDeclare方法和basicPublish方法小张总觉得不舒服。只看了两个消息队列,小张就不想再看了。他去找村长说:差别太大了,根本无法统一。村长说:“不要被复杂的现象蒙蔽了双眼,要看到背后的本质,适当抽象一下。”另一个抽象!小张暗暗感叹,这个抽象实在是太难了。“好好想想。”村长看出了小张的难处,鼓励他说:“其实也不难,先搞清楚几个基本概念,还记得我们在操作系统里学的生产者消费者吗?”作者的模型?我们可以在这里应用,消息生产者(MessageProducer),消息消费者(MessgeConsumer),生产者提供发送消息的方法,消费者提供接收消息的方法。如果加上消息队列(MessageQueue)是这样的:”小张说:“这个太抽象了,我看别人有QueueManager,Connection,Channel等等。”村长说:“不要着急,你看,无论是生产用户向队列发送消息,还是消费者接收消息,其实都是在和消息队列进行交互,所以我们引入一个会话(Session)的概念。”“哦,我明白一点,Session可以创建消息,也可以引入事务支持。《小张思维敏捷》不错。其实消息生产者/消费者也应该是通过Session来创建的,因为他们必须在一个session中发送/接收消息。另外大家想想,Session对象是谁来创建的呢?”小张说:“应该是Connection。”说着,小张画了一张图:“你看,概念出来了,是不是很简单?”村长笑着说。小张挠了挠头说:“遇者不难,难者不难。顺便说一句,我们还缺少最关键的连接参数(ip地址、端口等)和队列名称等信息。我们应该如何处理这些信息?“真的很复杂,每个厂商的具体情况差异太大了。”村长也表示难为情,“你让我考虑一下,下午再说。”3、配置和代码分离我在想,这些复杂的配置参数怎么办,如果让程序员写在代码里,那就太丑了,因为不同的MQ产品,配置是不一样的。下午,看到村长满脸笑容,小张就知道问题解决了。村长说:“我想到了一个办法,一个很简单但是很有效的办法。”小张道:“你别耍花样,说说就行了。这种方式就是把配置和代码分开。不是说这些connection参数很复杂,每个厂家都不一样吗?”把它作为配置信息放到web容器中,对外只提供一个简单的ConnectionFactory接口,ConnectionFactory就是用来创建Connection的.当然,每个厂商都必须实现这个ConnectionFactory""我们怎样才能得到这个ConnectionFactory?""很简单,对于程序员来说,可以通过JNDI很容易地获得,例如:""这是隐藏细节的好方法.既然ConnectionFactory可以做到这一点,那么Queue的配置信息也可以。”村长说:“所以ConnectionFactory,Queue是一个抽象层,隔离细节。4.再次,抽象的标准接口已经初具规模。肖张某很高兴,晚上请他喜欢的张二妮吃饭,不禁愣住了。张二妮说:“你们两个老土,定义的标准接口已经过时了.!小张很生气:“这怎么可能?”二妮说:“我告诉你,你建立的这个模型叫做PointtoPoint模型,就是一个发送者对应一个接收者。/订阅模式,你知道吗?”“一个客户端(Client1)向一个Topic发布一条消息,许多订阅了这个Topic的客户端(Client2,Client3)都可以收到这条消息的副本。”小张惊呆了,这和以前的ZhangMQ方式完全不一样,队列没有了,引入了一个新的主题(Topic)概念。第二天,小张就赶紧去找村长,告诉他新的一个话题(Topic)概念。村长说:“你还是太小了,慌什么,好好想想,这个publish/subscribe的本质和我们之前的producer/consumer没什么区别。”小张说:“那他们还有Topic这个概念。”“我们可以把Topic和Queue变成一个更抽象的概念。它们都是消息的目的地。好吧,它们被称为目的地。这个Destination的详细信息也需要通过JNDI进行配置和获取。“如何处理订阅?”村长说:“我们原来定义了MessageConsumer,现在我们新增了一个概念,叫做TopicSubscriber,可以从Destination获取消息,这还不够,其实Subscriber本质上也是消息消费者的一种而已。”“如何订阅功能可以实现吗?”“别忘了,我们只定义了接口行为,具体实现需要每个产品负责!”小张看着这幅画,感受到了抽象的强大力量。很多细节都变成了这些简单的概念!小张还特意写了一段代码来展示上面的概念:张家村提交了这个设计,帝国很满意,给它取名为JavaMessageService(JMS),然后各大产品都强制实现了JMS,否则不会签发北京入境许可证。没有这个许可证,别想在帝国做生意!JMS具有良好的设计和清晰的概念。其实不用勉强,很快就流行起来了,已经成为Java帝国事实上的标准。【本文为专栏作家“刘欣”原创稿件,转载请通过作者微信获取授权公众号coderising】点此查看作者更多好文
