当前,CORBA、DCOM、RMI等RPC中间件技术已经广泛应用于各个领域。但是这些中间件的局限性很明显,主要表现在以下方面:
(1)同步通信:客户发出调用后,必须等待服务对象的完成处理并返回结果后才能继续执行。
(2)客户和服务对象的生命周期紧密耦合:客户进程和服务对象进程都必须正常运行;如果服务对象崩溃或者网络故障导致客户的请求不可达,客户会接收到异常。
(3)点对点通信:客户的一次调用只发给某个单独的目标对象。
MOM(Message Oriented Middleware)面向消息的中间件较好的解决了以上问题。
发送者将消息发送给消息服务器,消息服务器将消息存放在若干队列中,在合适的时候再将消息转发给接收者。
这种模式下,发送和接收是异步的,发送者无须等待;
二者的生命周期未必相同:发送消息的时候接收者不一定运行,接收消息的时候发送者也不一定运行;
一对多通信:对于一个消息可以有多个接收者。
已经有的MOM系统有:IMB的MQSeries、Microsoft的MSMQ、BEA的MessageQ、Apache的ActiveMQ等。
由于没有一个通用的标准,这些系统很难相互操作和无缝连接。
JMS(Java Message Service)是SUN提出的一种MOM系统接口的规范,他包含点对点(Point to Point,PTP)和发布/订阅(Publish/Subscribe,pub/sub)两种消息模型。提供可靠消息传输、事务和消息过滤等机制。
总的来说,中间件屏蔽了底层操作系统的复杂性,使程序开发人员面对一个简单而统一的开发环境,减少了程序设计的复杂性,将注意力集中与自己的业务上,不必再为程序在不同软件系统上的移植而重复工作,从而大大减少了技术上的负担。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
本例中,使用Apache 的ActiveMQ来作为JMS中间件,这是一款相当成熟且开源的产品,得到了许多业内人士的好评。
首先需要下载Apache的ActiveMQ :http://activemq.apache.org/download.html
本例下载是
ActiveMQ 5.6.0 Release
解压后,打开里面的conf/activemq.xml
修改以下配置:
<transportConnectors>
<transportConnector name="openwire" uri="tcp://localhost:61616/"/>
</transportConnectors>
打开/bin/activemq.bat 启动即可!
如果是到正式环境,此ActiveMQ需要单独部署,然后供Spring 的JMS调用即可!
下面配置Spring的JMS环境:
ApplicationContext.xml
<!-- 定义JMS连接工厂 -->
<bean id="jmsFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
<!-- 定义JMS Template -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsFactory" />
</bean>
<!-- 定义消息目的地 -->
<bean id="dreamDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="dream.force" />
</bean>
<!-- 定义接收监听器 -->
<bean id="myTextListener" class="com.spring.jms.TextListener"></bean>
<!-- 定义一个JMS话题 -->
<bean id="jmsTopic" class="org.apache.activemq.command.ActiveMQTopic" autowire="constructor">
<constructor-arg value="STOCKS.Dreamforce.jms" />
</bean>
<!-- 定义消费者(接收端) -->
<bean id="javaConsumer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="jmsFactory" />
<property name="destination" ref="dreamDestination" />
<property name="messageListener" ref="myTextListener" />
</bean>
<!-- 定义发布者 -->
<bean id="publisher" class="com.spring.jms.SpringPublish">
<property name="template">
<ref local="jmsTemplate" />
</property>
<property name="destinations" ref="dreamDestination" />
</bean>
需要的Jar文件:
××××××××××××××××××××××××××××××××××××××××××××××××××
<!-- with spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jms_1.1_spec</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>activemq-core</groupId>
<artifactId>activemq-core</artifactId>
<version>5.6.0</version>
</dependency>
<dependency>
<groupId>javax.management.j2ee</groupId>
<artifactId>management-api</artifactId>
<version>1.1-rev-1</version>
</dependency>
<dependency>
<groupId>slf4j-api</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
××××××××××××××××××××××××××××××××××××××××××××××××××
1.消息监听器(TextListener.java):
public class TextListener implements MessageListener {
public void onMessage(Message message) {
ActiveMQMapMessage msg = null;
ActiveMQTextMessage ms = null;
//System.out.println("ONMessage-----------------" + message.toString());
try {
if (message instanceof ActiveMQMapMessage) {
msg = (ActiveMQMapMessage) message;
//String sentDate = msg.getString("date");
//String reMessage = msg.getString("message");
//int sentCount = msg.getInt("count");
//System.out.println("-------------New Message Arrival-----------"
// + new Date());
//System.out.println("It's " + sentCount + " time From Darcy: "
// + reMessage + " ---Send time :" + sentDate);
}else if(message instanceof ActiveMQTextMessage){
ms = (ActiveMQTextMessage)message;
System.out.println("他:"+ms.getText());
}
} catch (JMSException e) {
System.out.println("JMSException in onMessage(): " + e.toString());
} catch (Throwable t) {
System.out.println("Exception in onMessage():" + t.getMessage());
}
}
}
2.消息发布端(SpringPublish.java):
public class SpringPublish {
private JmsTemplate template;
private Destination[] destinations;
public void chart() {
boolean chart = true;
int count = 0;
while (chart) {
count++;
Scanner cin = new Scanner(System.in);
//System.out.println("输入聊天内容,输入exit停止聊天");
String text = cin.nextLine();
if (text.equals("exit")) {
chart = false;
}
System.out.println("我:" + text);
sendChartMessage(count, text);
}
}
protected void sendChartMessage(int count, String strMessage) {
MyMessageCreator creator = new MyMessageCreator(count, strMessage);
template.send(destinations[0], creator);
}
public JmsTemplate getTemplate() {
return template;
}
public void setTemplate(JmsTemplate template) {
this.template = template;
}
public Destination[] getDestinations() {
return destinations;
}
public void setDestinations(Destination[] destinations) {
this.destinations = destinations;
}
}
3.消息生产者(MyMessageCreator.java):
public class MyMessageCreator implements MessageCreator {
private int msgNo;
private String strMessage;
public MyMessageCreator(int no, String paramMessage) {
this.msgNo = no;
this.strMessage = paramMessage;
}
public Message createMessage(Session session) throws JMSException {
MapMessage message = session.createMapMessage();
message.setString("date", new Date().toString());
message.setString("message", strMessage);
message.setInt("count", msgNo);
return message;
}
}
4.测试类:
public class SpringJmsTestMain {
private SpringPublish publisher;
private DefaultMessageListenerContainer javaConsumer;
public SpringPublish getPublisher() {
return publisher;
}
public void setPublisher(SpringPublish publisher) {
this.publisher = publisher;
}
public void testJMS() {
javaConsumer.start();
publisher.chart();
}
public void setJavaConsumer(DefaultMessageListenerContainer javaConsumer) {
this.javaConsumer = javaConsumer;
}
public DefaultMessageListenerContainer getJavaConsumer() {
return javaConsumer;
}
public static void main(String[] args){
SpringJmsTestMain spring = new SpringJmsTestMain();
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
spring.setPublisher((SpringPublish)context.getBean("publisher"));
spring.setJavaConsumer((DefaultMessageListenerContainer)context.getBean("javaConsumer"));
spring.testJMS();
}
测试结果:
1.在Console中输入一些字符然后回车
2.打开http://localhost:8161/admin/
3.选择Queues,然后会看到你所发送的信息,如下图:
点击Send To 后:
控制台信息为: