Why Messageing
1、Asynchrony(异步)
2、Decoupling(解耦)
3、Reliability(可靠)
4、Support for multiple senders and receivers(多点发送,多点接受)
面向消息编程也可以说时一种SOA的实现。
中间通过消息中间件,缓存和分发消息。
Message Oriented Middleware(MOM)
1、MOM is a term used to refer to any infrastructure that supports messaging
2、MOM products
The Java Message Service(JMS)
目标:使用统一的API 去访问不同的消息服务中间件
1、Is a messaging standard designed to eliminate many of the disadvantages that MOM-based products faced
2、Has two parts
we use it to write code to send and receive messages
Plug in JMS providers
A JMS provider knows how to talk to a specific MOM implementation
Messaging Domains
消息的两种方式
1、发布/订阅 的方式 , 基于主题的
2、点对点 的方式 , 基于队列的
Client View of a JMS System
使用Jboss部署 Topic/Queue
1、打开Jboss控制台(http://localhost:8080/jmx-console/)
2、找到域 jboss.mq , 找到服务 service=DestinationManager(目标管理器)
3、这个bean提供了创建队列和主题的方法(createQueue()和createTopic()),都需要2个参数,一个名字,一个JNDI名字
例子:创建队列
可以再控制台查看到此队列:(这些都是临时的,重启服务后就没了,不过可以通过配置文件预先创建)
通过客户端去连接
点对点的
创建生产者:
import javax.jms.*; import javax.naming.*; public class Producer{ public static void main(String[] args)throws NamingException{ Context ctx = new InitialContext(); ConnectionFactory cf = (ConnectonFactory)ctx.lookup("ConnectionFactory");//名字在Jboss中缺省就叫ConnectionFactory Destination des = (Destination)ctx.lookup("queue/Testqueue");//查询目标 Connection con = cf。createConnection();//创建连接 Session session = con.createSession(false,Session.AUTO_ACKNOWLEDGE);/*创建会话,第一个参数标示是否使用事务,第二个表示自动通知,指收到消息后自动恢复消息中间件,中间件就会认为你收到了然后把消息删除,如果不是自动通知则意味可以重复接受消息,在这里是生产者,这个参数没有意思,但API如此,只能写。*/ MessageProducer producer = session.createProducer(des);//创建消息生产者,传入基于的目标 TextMessage msg = session.createTextMessage();//创建message,这里TextMessage是一个子类。 msg.setText("clat"); producer.send(mgs); con.close(); System.out.println("over!"); } }
创建消费者:
import javax.jms.*; import javax.naming.*; public class Producer{ public static void main(String[] args)throws NamingException{ Context ctx = new InitialContext(); ConnectionFactory cf = (ConnectonFactory)ctx.lookup("ConnectionFactory");//名字在Jboss中缺省就叫ConnectionFactory Destination des = (Destination)ctx.lookup("queue/Testqueue");//查询目标 Connection con = cf。createConnection();//创建连接 Session session = con.createSession(false,Session.AUTO_ACKNOWLEDGE);/*创建会话,第一个参数标示是否使用事务,第二个表示自动通知,指收到消息后自动恢复消息中间件,中间件就会认为你收到了然后把消息删除,如果不是自动通知则意味可以重复接受消息。*/ MessageConsumer consumer = session.createConsumer(des); con.start();//通知消息中间件,准备就绪,可以分发消息了 Message message = consumer.receive(); if(message instanceof TextMessage){ TextMessage msg = (Textmessage)message; String text = msg.getText(); System.out.println(text); } con.close(); } }
如果要改写为基于主题的 ,只需要修改Destination,改目标位主题就行
这里消费者,可以以另一种方式,监听器来完成消费消息,等于把消息当成一个事件处理,代码如下:
public class MyMessageListener implements MessageListener{ public void onMessage(Message message){ if(message instanceof TextMessage){ TextMessage msg = (TextMessage) message; String text; try{ text = msg.getText(); System.out.println(text); }catch(JMSException e){ e.printStackTrace(); } } } } public class Producer{ public static void main(String[] args)throws NamingException{ Context ctx = new InitialContext(); ConnectionFactory cf = (ConnectonFactory)ctx.lookup("ConnectionFactory");//名字在Jboss中缺省就叫ConnectionFactory Destination des = (Destination)ctx.lookup("queue/Testqueue");//查询目标 Connection con = cf。createConnection Session session = con.createSession(false,Session.AUTO_ACKNOWLEDGE MessageConsumer consumer = session.createConsumer(des); con.start(); // Message message = consumer.receive(); // if(message instanceof TextMessage){ // TextMessage msg = (Textmessage)message; // String text = msg.getText(); // System.out.println(text); // } // 注册消息监听器,他会单独起一个线程监听消息,主线程不会阻碍 consumer.setMessageListemer(new MyMessageListener()) //这里 就不能关闭连接了,因为监听器还在监听。 // con.close(); } }
在服务器中查看发送后在队列中缓存的消息
1、以jboss为例,在目标队列中,找到对应方法。
该方法,返回所有在当前队列中被缓存的方法:
例子,当前队列中只有一条消息,如下:
Header:消息头
Body:消息体
消息的类型
主要有以下几类:
进入正题了
Message-Driven Bean
1、A special EJB component that can receive JMS messages as well as other types of messages
2、Consumes messages from different destinations
3、MDB没有远程、本地业务接口。
4、与statless session bean 一样,是无状态的,可共享的,在容器中有共享池。
5、对于所有厂家提供的消息驱动bean, 起码支持JMS。(也可以支持soap等)
要支持JMS,那就要支持消息监听器(就是上面提到消费消息的第二种方法)
6、消息监听器的onMessage方法无返回值,也无排除异常,所以MDB也如此。
7、MDB是无状态的,不会负责维护用户的信息。
8、MDB是单线程。(EJB全是单线程的)
例子:
当消息到来时,容器会在共享池中找一个bean 进行处理,并把当前接受到得消息传递给他
这与之前自己处理消息有什么不同能?
1、我们不用考虑线程的问题了,MDB能处理消息大量的并发
2、能提供容器的种种服务,比如缺省提供的事务服务。
3、不过消息的顺序是没有保证的。
4、持久化订阅者:消费者肯定会再来,消息会缓存住等待消费者。
//mappedName在不同中间件服务器上意义不同,可能是jndi名。非必须 //activationConfig:激活配置。必须的 @MessageDriven(mappedName="jms/FirstMdb",activationConfig={ //通知类型,缺省EJB使用容器管理事务,这里声明无意义,去掉保留一样。 @ActivationConfigProperty(propertyName="acknowledgeMode",propertyValue="Auto-acknowledge"), //目标类型 @ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Queue"), //目标的JNDI名 @ActivationConfigProperty(propertyName="destination",propertyValue="queue/testQueue"),) }) public class FirstMdb implements MessageListener{ public void onMessage(Message message){ TextMessage msg = (TextMessage) message; String text; try{ text=mgs.getText(); System.out.println(text); }catch(JMSException e){ e.printStackTrace(); } } }