1. spring 和 amqp版本
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.1.RELEASE</version>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>1.6.0.RELEASE</version>
</dependency>
</dependencies>
2. 配置
<pre name="code" class="html"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd">
<!--配置connection-factory,指定连接rabbit server参数 -->
<rabbit:connection-factory id="connectionFactory"
username="admin" password="111111" host="123.56.99.80" port="5672" />
<!--定义rabbit template用于数据的接收和发送 -->
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"
exchange="myDirectExchange" routing-key="mq.test" />
<!--通过指定下面的admin信息,当前producer中的exchange和queue会在rabbitmq服务器上自动生成 -->
<rabbit:admin connection-factory="connectionFactory" />
<!--定义queue -->
<rabbit:queue name="myQueue" durable="true" auto-delete="false"
exclusive="false" />
<!-- 定义direct exchange,绑定queueTest -->
<rabbit:direct-exchange name="myDirectExchange"
durable="true" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="myQueue" key="mq.test" />
</rabbit:bindings>
</rabbit:direct-exchange>
<!-- <rabbit:topic-exchange name="myTopicExchange"> -->
<!-- <rabbit:bindings> -->
<!-- <rabbit:binding queue="myQueue" pattern="mq.*" /> -->
<!-- </rabbit:bindings> -->
<!-- </rabbit:topic-exchange> -->
<!-- 消息接收者 -->
<bean id="consumer" class="com.zybros.consumer.Consumer"></bean>
<bean id="consumer2" class="com.zybros.consumer.Consumer2"></bean>
<!-- queue litener 观察 监听模式 当有消息到达时会通知监听在对应的队列上的监听对象 -->
<rabbit:listener-container
connection-factory="connectionFactory">
<rabbit:listener queues="myQueue" ref="consumer" />
<!-- consumer 若想不实现MessageListener,可以用下面的 method指定, 个人认为这方式不错,consumer只是一个普通类就可以,侵入性低 -->
<!-- <rabbit:listener queue-names="myQueue" method="consume" ref="consumer2"/> -->
</rabbit:listener-container>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<import resource="classpath*:rabbitmq.xml" />
<!-- 扫描指定package下所有带有如@controller,@services,@resource,@ods并把所注释的注册为Spring Beans -->
<context:component-scan base-package="com.zybros.consumer,com.zybros.producer" />
<!-- 激活annotation功能 -->
<context:annotation-config />
<!-- 激活annotation功能 -->
<context:spring-configured />
</beans>
3. 代码
package com.zybros.producer;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Service;
import com.zybros.bean.User;
@Service
public class Producer {
private Logger logger = LoggerFactory.getLogger(Producer.class);
@Resource
private AmqpTemplate amqpTemplate;
public void produce(User user) {
logger.info("++++++++++++++++++++++++++");
logger.info("****** produce user: "+user.getName());
// //此处的routingkey 没有在xml中配置
// amqpTemplate.convertAndSend("queueKey", user);
//此处的routingkey 在xml中已经配置
amqpTemplate.convertAndSend(user);
}
}
package com.zybros.consumer;
import org.apache.commons.lang3.SerializationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import com.zybros.bean.User;
public class Consumer<E> implements MessageListener {
private Logger logger = LoggerFactory.getLogger(Consumer.class);
@Override
public void onMessage(Message message) {
logger.info("--------------");
User u = SerializationUtils.deserialize(message.getBody());
logger.info("****** consumer user: "+u.getName());
logger.info("****** consumer messageProperties: "+message.getMessageProperties());
}
}
package com.zybros.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zybros.bean.User;
import com.zybros.producer.Producer;
public class MQTest {
static ApplicationContext context = null;
public static void main(String[] s) {
try {
context = new ClassPathXmlApplicationContext("application.xml");
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void test1() throws Exception {
Producer producer = (Producer) context.getBean("producer");
int a = Integer.MAX_VALUE;
while (a > 0) {
User u = new User("name: " + a, "addr: " + a, a);
producer.produce(u);
a--;
try {
// 暂停一下,好让消息消费者去取消息打印出来
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// public static void test2() throws Exception {
// Producer2 producer = (Producer2) context.getBean("producer2");
// int a = Integer.MAX_VALUE;
// while (a > 0) {
// User u = new User("name2: "+a,"addr2: "+a,a);
// producer.produce(u);
// try {
// //暂停一下,好让消息消费者去取消息打印出来
// Thread.sleep(3000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// }
// }
}
4:输出结果
============================================================
consumer 若想不实现MessageListener,可以用下面的 method指定, 个人认为这方式不错,consumer只是一个普通类就可以,侵入性低
如下
package com.zybros.consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zybros.bean.User;
public class Consumer2<E>{
private Logger logger = LoggerFactory.getLogger(Consumer2.class);
public void consume(Object obj) {
User u = (User) obj;
logger.info("--------------");
logger.info("--------------");
logger.info(obj.toString());
logger.info(u.getName());
}
}
对应的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd">
<!--配置connection-factory,指定连接rabbit server参数 -->
<rabbit:connection-factory id="connectionFactory"
username="admin" password="111111" host="123.56.99.80" port="5672" />
<!--定义rabbit template用于数据的接收和发送 -->
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"
exchange="myDirectExchange" routing-key="mq.test" />
<!--通过指定下面的admin信息,当前producer中的exchange和queue会在rabbitmq服务器上自动生成 -->
<rabbit:admin connection-factory="connectionFactory" />
<!--定义queue -->
<rabbit:queue name="myQueue" durable="true" auto-delete="false"
exclusive="false" />
<!-- 定义direct exchange,绑定queueTest -->
<rabbit:direct-exchange name="myDirectExchange"
durable="true" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="myQueue" key="mq.test" />
</rabbit:bindings>
</rabbit:direct-exchange>
<!-- <rabbit:topic-exchange name="myTopicExchange"> -->
<!-- <rabbit:bindings> -->
<!-- <rabbit:binding queue="myQueue" pattern="mq.*" /> -->
<!-- </rabbit:bindings> -->
<!-- </rabbit:topic-exchange> -->
<!-- 消息接收者 -->
<bean id="consumer" class="com.zybros.consumer.Consumer"></bean>
<bean id="consumer2" class="com.zybros.consumer.Consumer2"></bean>
<!-- queue litener 观察 监听模式 当有消息到达时会通知监听在对应的队列上的监听对象 -->
<rabbit:listener-container
connection-factory="connectionFactory">
<!-- <rabbit:listener queues="myQueue" ref="consumer" /> -->
<!-- consumer 若想不实现MessageListener,可以用下面的 method指定, 个人认为这方式不错,consumer只是一个普通类就可以,侵入性低 -->
<rabbit:listener queue-names="myQueue" method="consume" ref="consumer2"/>
</rabbit:listener-container>
</beans>
5. 总结
逻辑
1. template 在发送消息时,指定对应的exchange,并设定routingkey。
2. 因在设置exchage时,binding中设置了 queue 同 key或者 pattern 的映射。因此会根据routingkey binding到对应的queue。
3. listenner-containner中设置的 listener 根据监听的queue 调用 consumer。
不足
这种监听模式感觉有一定的缺陷,正常情况下,producer生产到mq中的msg后,consumer监听到后调用对应的方法进行消费。 但若监听的consumer出了问题,不能正常进行消费,除了msg在mq中大量积压,造成一些消息一直在mq中,consumer却不知道,这也是一种消息的丢失。
当然可以用原始的方式去mq中主动读取msg,弥补解决这种问题,若是这样就没必要用listener。
另因本人没有细看springAMQP中的listener源码,只是在看console日志时,发现日志是每一秒执行一次Retrieving,若是这样感觉算不上好的listener。
估计应该只是日志本身的retrieving,spring的大牛不会犯这么低级的错误。
之后抽时间看下listener,再进行更正。
6. 代码
原demo 代码地址 http://download.csdn.net/detail/stonexmx/9572076