Java 消息服务(JMS)可以帮助我们减少应用程序间的耦合,而同时又允许应用程序间的通信以及使用对方的资源。JMS 一般都包含至少三个组成部分:两个JMS 客户和一个 JMS 服务器。两个客户通过 JMS 服务器相互通信。JMS 客户是使用 JMS API发送和接收消息的常规应用程序。
JMS 服务器可以是任何实现 JMS 规范的应用程序。一些 JMS 服务器是更大的应用程序的一部分;还有一些是专门负责 JMS 任务的应用程序。有很多第三方商业资源和一些开放源代码资源的 JMS 服务器可供选择使用。应用程序使用 JMS 相互通信有两个方法可以选用:JMS 主题和 JMS 队列。主题和队列只在很少一些地方有区别,其中最明显的区别是它们发送消息的方式不同。
JMS 主题从一个 JMS 客户接收消息然后将这些消息分发给所有注册为主题监听者的 JMS 客户。相反,JMS 队列只将消息分发给一个客户,不管有多少客户注册为队列监听者。如果两个或者多个客户注册到一个队列,同时一个消息存储在队列中,那么只有一个客户能接收到这个消息。
JMS 规范没有规定哪个客户将接收这个消息。不管你是使用 JMS 主题还是 JMS 队列,消息中所要传递的数据的类型都在于你自己。一些程序员通过他们的消息系统发送商业对象,而其它程序员以文本格式发送 XML 消息从而进一步地减少耦合。如果你以前没有用过 JMS,那么可能是因为你还没有一个使用它的原因。如果你以前编写过你自己的消息系统,那么很可能你将从 JMS API 中受益。
JRun服务器已经提供了对JMS的支持,且内置了JMS服务,以JRun4.0为例,主要配置文件有{JRun-Home}/server/servers/{server-name}/SERVER-INF/jrun-jms.xml和jrun-resources.xml,查看jrun-jms.xml文件可以知道jrun对于JMS Message的持久化有两种方式,一个是文件方式,一个是数据库方式,默认是文件来保存JMS Message:
<active-adapter-type>file</active-adapter-type>
<persistence-adapter>
<adapter-type>file</adapter-type>
</persistence-adapter>
<persistence-adapter>
<adapter-type>rdbm</adapter-type>
</persistence-adapter>
</persistence-manager>
这里需要注意的就是把<client-jndi>的注释去掉,并修改provider-url为服务器实际地址,此处为例为192.168.2.240:2908,注意2908是此Server提供的JNDI服务端口,因为JMS服务是绑定到server的JNDI服务上的,客户端需要查询JNDI。再修改run-resources.xml添加测试的JMS队列(也可以通过JRun控制台添加)
< jndi - name > jms / queue / testQueue </ jndi - name >
< destination - name > testQueue </ destination - name >
< destination - type > javax.jms.Queue </ destination - type >
</ jms - destination >
再添加QueueConnectionFactory
< factory - name > QueueConnectionFactory </ factory - name >
< jndi - name > jms / jndi - QueueConnectionFactory </ jndi - name >
< type > javax.jms.QueueConnectionFactory </ type >
< transport > RMI </ transport >
< username > guest </ username >
< password > guest </ password >
</ jms - connection - factory >
上面transport是指传输消息所用的协议,RMI:java远程方法调用,TCP:TCP/IP协议,Intra-VM:只在本虚拟机传输消息,用户名/密码是服务验证客户端调用时使用。服务器端JMS的设置基本完成了,还需要设置jrun的安全策略。
修改{JRun-Home}/server/security.properties,有两项jrun.subnet.restriction:子网掩码,jrun.trusted.hosts:信任主机的IP,否则远程调用可能会被拒绝。再到{JRun-Home}/bin下修改jvm.config,添加java虚拟机启动参数-Djava.rmi.server.hostname=192.168.2.240,其中192.168.2.240为主机的实际IP,不要写localhost,否则RMI的远程调用会被拒绝。也可以写一个新配置文件new-server.conf,启动时用命令jrun –config new-server.conf –start XXX指定配置文件。服务器端的设置完成。当然如果客户端程序也在此JRun中运行,可以忽略这些参数的修改和设置。
客户端的代码基本与调用其他JMS服务类似。注意要取得{JRun-Home}/lib/jrun.jar并放入到客户端环境的classpath中,代码示例
private Context context = null;
private QueueConnection connection = null;
private QueueSession session = null;
private Queue queue = null;
private QueueSender sender = null;
private String connectionFactory;
private String queueJndiName;
public void setConnectionFactory(String connectionFactory)...{
this.connectionFactory = connectionFactory;
}
public void setQueueJndiName(String queueJndiName)...{
this.queueJndiName = queueJndiName;
}
/** *//**
* 初始化JMS队列
* @param ctxFactory
* @param url
* @param user
* @param pwd
* @throws Exception
*/
public void init(String ctxFactory,String url,String user,String pwd)throws Exception ...{
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY,ctxFactory);
p.put(Context.PROVIDER_URL,url);
p.put(Context.SECURITY_PRINCIPAL,user);
p.put(Context.SECURITY_CREDENTIALS,pwd);
context = new InitialContext(p);
QueueConnectionFactory factory = (QueueConnectionFactory)context.lookup(connectionFactory);
connection = factory.createQueueConnection();
queue = (Queue)context.lookup(queueJndiName);
session = connection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
sender = session.createSender(queue);
connection.start();
}
/** *//**
* 发送文本消息
* @param txt
* @throws Exception
*/
public void send(String txt)throws Exception ...{
TextMessage tmsg = session.createTextMessage();
tmsg.setText(txt); sender.send(tmsg);
}
/** *//**
* 查询队列中保存的消息
* @throws Exception
*/
public void browser()throws Exception...{
QueueBrowser browser = session.createBrowser(queue);
Enumeration enum = browser.getEnumeration();System.out.println("QueueBrowser");
while (enum.hasMoreElements())...{
System.out.println(enum.nextElement());
}
browser.close();
}
/** *//**
* 接收消息
* @throws Exception
*/
public void receive()throws Exception...{
QueueReceiver receiver = session.createReceiver(queue);
while(true)...{
TextMessage message = (TextMessage)receiver.receiveNoWait();
if(message == null)break;
System.out.println("receive message:" + message.getText());
}
receiver.close();
}
public void close()throws Exception...{
sender.close();
session.close();
connection.close();
context.close();
}
public static void main(String[] args)throws Exception ...{
String ctxFactory = "jrun.naming.JRunContextFactory";
String url = "192.168.2.240:2908";
String user = "guest";
String pwd = "guest";
String connectionFactoryJndi = "jms/jndi-QueueConnectionFactory";
String queueJndi = "jms/queue/testQueue";
JmsQueueTest test = new JmsQueueTest();
test.setConnectionFactory(connectionFactoryJndi);
test.setQueueJndiName(queueJndi);
test.init(ctxFactory,url,user,pwd);
test.send("java共舞JMS消息");
test.browser();
test.receive();
test.close();
}