1.导入依赖
<properties>
.....
<!-- spring -->
<spring.version>5.1.1.RELEASE</spring.version>
<!-- log4j日志包版本号 -->
<slf4j.version>1.7.18</slf4j.version>
<log4j.version>1.2.17</log4j.version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- AOP-AspectJ spring-aop依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.6</version>
</dependency>
<!-- 添加日志相关jar包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- rabbitmq -->
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>1.7.5.RELEASE</version>
</dependency>
.....
</dependencies>
2.创建配置文件
a.创建 spring.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 自动扫描的包名 -->
<context:component-scan base-package="com.wode" />
<!-- 开启AOP代理 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!--开启注解处理器 -->
<context:annotation-config>
</context:annotation-config>
<context:property-placeholder location="classpath:rabbit.properties"/>
<!-- Spring中引入其他配置文件 -->
<import resource="classpath*:/spring-rabbit.xml" />
</beans>
b.创建 spring-rabbit.xml
<?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.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.2.xsd">
<!-- ============================================公共部分============================================ -->
<!-- 创建连接类 连接安装好的 rabbitmq -->
<rabbit:connection-factory id="connectionFactory" host="${rabbit.ip}" port="${rabbit.port}" username="${rabbit.username}" password="${rabbit.password}" />
<rabbit:admin connection-factory="connectionFactory"/>
<!-- spring amqp默认的是jackson 的一个插件,目的将生产者生产的数据转换为json存入消息队列 -->
<bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" />
<!-- ============================================direct路由模式============================================ -->
<!--定义消息队列,durable:是否持久化,如果想在RabbitMQ退出或崩溃的时候,不会失去所有的queue和消息,需要同时标志队列(queue)和交换机(exchange)是持久化的,即rabbit:queue标签和rabbit:direct-exchange中的durable=true,而消息(message)默认是持久化的可以看类org.springframework.amqp.core.MessageProperties中的属性public static final MessageDeliveryMode DEFAULT_DELIVERY_MODE = MessageDeliveryMode.PERSISTENT;exclusive: 仅创建者可以使用的私有队列,断开后自动删除;auto_delete: 当所有消费客户端连接断开后,是否自动删除队列 -->
<rabbit:queue name="direct.queue.1" id="direct.queue.1" durable="true" auto-delete="false" exclusive="false" />
<rabbit:queue name="direct.queue.2" id="direct.queue.2" durable="true" auto-delete="false" exclusive="false" />
<!--绑定队列,rabbitmq的exchangeType常用的三种模式:direct,fanout,topic三种,我们用direct模式,即rabbit:direct-exchange标签,Direct交换器很简单,如果是Direct类型,就会将消息中的RoutingKey与该Exchange关联的所有Binding中的BindingKey进行比较,如果相等,则发送到该Binding对应的Queue中。有一个需要注意的地方:如果找不到指定的exchange,就会报错。但routing key找不到的话,不会报错,这条消息会直接丢失,所以此处要小心,auto-delete:自动删除,如果为Yes,则该交换机所有队列queue删除后,自动删除交换机,默认为false -->
<rabbit:direct-exchange id="direct.exchange" name="direct.exchange" durable="true" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="direct.queue.1" key="${routing.1}"></rabbit:binding>
<rabbit:binding queue="direct.queue.2" key="${routing.2}"></rabbit:binding>
</rabbit:bindings>
</rabbit:direct-exchange>
<rabbit:template exchange="direct.exchange" id="rabbitTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter" />
<!-- 消费者部分 -->
<!-- 自定义接口类 -->
<bean id="directConsumerAuto" class="com.wode.direct.DirectConsumerAuto"></bean>
<bean id="directConsumerManual" class="com.wode.direct.DirectConsumerManual"></bean>
<!-- 配置监听acknowledeg="manual"设置手动应答,它能够保证即使在一个worker处理消息的时候用CTRL+C来杀掉这个worker,或者一个consumer挂了(channel关闭了、connection关闭了或者TCP连接断了),也不会丢失消息。因为RabbitMQ知道没发送ack确认消息导致这个消息没有被完全处理,将会对这条消息做re-queue处理。如果此时有另一个consumer连接,消息会被重新发送至另一个consumer会一直重发,直到消息处理成功,监听容器acknowledge="auto" concurrency="30"设置发送次数,最多发送30次 -->
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto" concurrency="20">
<rabbit:listener queues="direct.queue.1" ref="directConsumerAuto" />
</rabbit:listener-container>
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual" concurrency="20">
<rabbit:listener queues="direct.queue.2" ref="directConsumerManual" />
</rabbit:listener-container>
<!-- ============================================fanout订阅推送模式============================================ -->
<!--定义消息队列-->
<rabbit:queue name="fanout.queue.1" id="fanout.queue.1" durable="true" auto-delete="false" exclusive="false" />
<rabbit:queue name="fanout.queue.2" id="fanout.queue.2" durable="true" auto-delete="false" exclusive="false" />
<!-- Fanout 扇出,顾名思义,就是像风扇吹面粉一样,吹得到处都是。如果使用fanout类型的exchange,那么routing key就不重要了。因为凡是绑定到这个exchange的queue,都会受到消息。 -->
<rabbit:fanout-exchange id="fanout.exchange" name="fanout.exchange" durable="true" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="fanout.queue.1"></rabbit:binding>
<rabbit:binding queue="fanout.queue.2"></rabbit:binding>
</rabbit:bindings>
</rabbit:fanout-exchange>
<rabbit:template exchange="fanout.exchange" id="fanoutRabbitTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter" />
<!-- 消费者部分 -->
<!-- 自定义接口类 -->
<bean id="fanoutConsumerAuto" class="com.wode.fanout.FanoutConsumerAuto"></bean>
<bean id="fanoutConsumerManual" class="com.wode.fanout.FanoutConsumerManual"></bean>
<!-- 配置监听acknowledeg="manual"设置手动应答,它能够保证即使在一个worker处理消息的时候用CTRL+C来杀掉这个worker,或者一个consumer挂了(channel关闭了、connection关闭了或者TCP连接断了),也不会丢失消息。因为RabbitMQ知道没发送ack确认消息导致这个消息没有被完全处理,将会对这条消息做re-queue处理。如果此时有另一个consumer连接,消息会被重新发送至另一个consumer会一直重发,直到消息处理成功,监听容器acknowledge="auto" concurrency="30"设置发送次数,最多发送30次 -->
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto" concurrency="20">
<rabbit:listener queues="fanout.queue.1" ref="fanoutConsumerAuto" />
</rabbit:listener-container>
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual" concurrency="20">
<rabbit:listener queues="fanout.queue.2" ref="fanoutConsumerManual" />
</rabbit:listener-container>
<!-- ============================================topic模式============================================ -->
<!--定义消息队列-->
<rabbit:queue name="topic.queue.1" id="topic.queue.1" durable="true" auto-delete="false" exclusive="false" />
<rabbit:queue name="topic.queue.2" id="topic.queue.2" durable="true" auto-delete="false" exclusive="false" />
<!-- 发送端不是按固定的routing key发送消息,而是按字符串“匹配”发送,接收端同样如此 -->
<rabbit:topic-exchange id="topic.exchange" name="topic.exchange" durable="true" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="topic.queue.1" pattern="order.*" />
<rabbit:binding queue="topic.queue.2" pattern="*.insert" />
</rabbit:bindings>
</rabbit:topic-exchange>
<rabbit:template exchange="topic.exchange" id="topicRabbitTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter" />
<!-- 消费者部分 -->
<!-- 自定义接口类 -->
<bean id="topicConsumerAuto" class="com.wode.topic.TopicConsumerAuto"></bean>
<bean id="topicConsumerManual" class="com.wode.topic.TopicConsumerManual"></bean>
<!-- 配置监听acknowledeg="manual"设置手动应答,它能够保证即使在一个worker处理消息的时候用CTRL+C来杀掉这个worker,或者一个consumer挂了(channel关闭了、connection关闭了或者TCP连接断了),也不会丢失消息。因为RabbitMQ知道没发送ack确认消息导致这个消息没有被完全处理,将会对这条消息做re-queue处理。如果此时有另一个consumer连接,消息会被重新发送至另一个consumer会一直重发,直到消息处理成功,监听容器acknowledge="auto" concurrency="30"设置发送次数,最多发送30次 -->
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto" concurrency="20">
<rabbit:listener queues="topic.queue.1" ref="topicConsumerAuto" />
</rabbit:listener-container>
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual" concurrency="20">
<rabbit:listener queues="topic.queue.2" ref="topicConsumerManual" />
</rabbit:listener-container>
</beans>
c.创建 rabbit.properties
#RabbitMQ服务器地址,默认值"localhost"
rabbit.ip=localhost
#RabbitMQ服务端口,默认值为5672
rabbit.port=5672
#访问RabbitMQ服务器的账户,默认是guest
rabbit.username=guest
#访问RabbitMQ服务器的密码,默认是guest
rabbit.password=guest
#路由标识
routing.1=1
routing.2=2
3.创建生产者
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class CommonProducer {
//direct模式
@Resource(name = "rabbitTemplate")
private AmqpTemplate rabbitTemplate;
@Value("${routing.1}")
private String routing1;
@Value("${routing.2}")
private String routing2;
//fanout模式
@Resource(name = "fanoutRabbitTemplate")
private AmqpTemplate fanoutRabbitTemplate;
//topic模式
@Resource(name = "topicRabbitTemplate")
private AmqpTemplate topicRabbitTemplate;
public void send(){
rabbitTemplate.convertAndSend(routing1, "routing1");
rabbitTemplate.convertAndSend(routing2, "routing2");
fanoutRabbitTemplate.convertAndSend("fanoutMsg");
topicRabbitTemplate.convertAndSend("order.insert", "order.insert");
topicRabbitTemplate.convertAndSend("order.update", "order.update");
}
}
4.创建direct模式消费者
a.自动提交消费者,对应配置文件中 acknowledge="auto"
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
public class DirectConsumerAuto implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg = new String(message.getBody(),"UTF-8");
System.out.println("[DirectConsumerAuto]消费者接收到:" + msg);
}
}
b.手动提交消费者,对应配置文件中 acknowledge="manual"
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
public class DirectConsumerManual implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg = new String(message.getBody(),"UTF-8");
System.out.println("[DirectConsumerManual]消费者接收到:" + msg);
//手动确认
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
}
}
5.创建fanout模式消费者
a.自动提交消费者,对应配置文件中 acknowledge="auto"
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
public class FanoutConsumerAuto implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg = new String(message.getBody(),"UTF-8");
System.out.println("[FanoutConsumerAuto]消费者接收到:" + msg);
}
}
b.手动提交消费者,对应配置文件中 acknowledge="manual"
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
public class FanoutConsumerManual implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg = new String(message.getBody(),"UTF-8");
System.out.println("[FanoutConsumerManual]消费者接收到:" + msg);
//手动确认
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
}
}
6.创建topic模式消费者
a.自动提交消费者,对应配置文件中 acknowledge="auto"
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
public class TopicConsumerAuto implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg = new String(message.getBody(),"UTF-8");
System.out.println("[TopicConsumerAuto]消费者接收到:" + msg);
}
}
b.手动提交消费者,对应配置文件中 acknowledge="manual"
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
public class TopicConsumerManual implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg = new String(message.getBody(),"UTF-8");
System.out.println("[TopicConsumerManual]消费者接收到:" + msg);
//手动确认
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
}
}
7.测试
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
CommonProducer commonProducer = (CommonProducer) applicationContext.getBean("commonProducer");
commonProducer.send();
}