spring集成rabbitmq实现消息队列

  1. RabbitTemplate概念了解

RabbitMQ是由Erlang(爱立信公司)语言开发,实现Advanced Message Queuing Protocol (AMQP高级消息队列协议)的消息中间件。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。

• Broker:消息队列服务器实体,例如RabbitMQ服务
• Vhost:虚拟主机,默认为“/”,一个broker里可以有多个vhost,区分不同用户权限,类似java的命令空间
• Connection:应用程序与broker连接,可有多个连接
• Channel:消息通道,connection中可建立多个channel,每个channel代表一个会话任 务,所有操作都在channel中进行。
• Exchange:消息交换机,channel中可有多个,用于投递消息。应用程序发送消息时先把消息给交换机,由交换机投递给队列,不是直接给队列。
类型有三种:fanout(广播)、Direct(处理路由键,轮播实现)、Topic(支持消息模糊匹配)
• Queue:队列,用于存放消息
• Message:消息,应用程序需要发送的数据
• Bind:根据routingKey绑定exchange与queue规则,决定消息发送的方向

需要添加的jar包

        <!--rabbit -->
        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
  1. 生产者

spring集成rabbitMQ后实现的工具类,只需要在spring配置文件中配置即可
思路: 1. 配置连接工厂(与原生实现一样) —> 2. 配置spring的admin —> 3.创建队列 —> 4.创建交换器,并绑定队列 —> 5.配置连接模板 ,这样就完成了生产者的配置了。

<!-- rabbitMQ配置 -->
	<bean id="rabbitConnectionFactory"
        class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
        <constructor-arg value="127.0.0.1"/>
        <property name="username" value="guest"/>
        <property name="password" value="guest"/>
        <property name="channelCacheSize" value="8"/>
        <property name="port" value="5672"></property>
    </bean>
    <!--Spring的rabbitmq admin-->
    <!-- 创建rabbitAdmin 代理类 -->
    <rabbit:admin connection-factory="rabbitConnectionFactory"/>


	<!--配置队列queue, Exchange, 以及将他们结合在一起的binding-->
    <!--在queue以及exchange中, 有一个重要的属性durable, 默认为true, 可以防止宕机后数据丢失。-->
    <!--在listener-container中, 有acknowledge属性, 默认为auto, 即消费者成功处理消息后必须有个应答, 如果消费者程序发生异常或者宕机, 消息会被重新放回队列-->
    
   <!--生产者创建队列-->
    <rabbit:queue name="p_create_queue" durable="false"/>

    <!--标准的AMQP Exchange有4种: Direct, Topic, Headers, Fanout, 根据实际需要选择。-->
    <!--Direct: 如果消息的routing key与bingding的routing key直接匹配的话, 消息将会路由到该队列上。-->
    <!--Topic: 如果消息的routing key与bingding的routing key符合通配符匹配的话, 消息将会路由到该队列上。-->
    <!--Headers: 如果消息参数表中的头信息和值都与binding参数表中相匹配, 消息将会路由到该队列上。-->
    <!--Fanout: 不管消息的routing key和参数表的头信息/值是什么, 消息将会路由到该队列上。-->
    
	<!--fanout交换器-->
    <rabbit:fanout-exchange name="fanout-exchange"
        xmlns="http://www.springframework.org/schema/rabbit" durable="false">
        <rabbit:bindings>
            <rabbit:binding queue="p_create_queue"></rabbit:binding>
        </rabbit:bindings>
    </rabbit:fanout-exchange>

	<!--topic交换器-->
    <rabbit:topic-exchange name="topic-exchange"
         xmlns="http://www.springframework.org/schema/rabbit" durable="false">
    </rabbit:topic-exchange>
	<!-- rabbitTemplate 消息模板类 -->

    <!-- 消息发送重试 ,可选项-->
    <bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
        <property name="backOffPolicy">
            <bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
                <property name="initialInterval" value="500" />
                <property name="multiplier" value="10.0" />
                <property name="maxInterval" value="10000" />
            </bean>
        </property>
    </bean>

    <!--定义Spring的RabbitMQ的连接模板  -->
    <bean id="rabbitTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate">
        <constructor-arg ref="rabbitConnectionFactory"></constructor-arg>
    </bean>

代码中实现发送消息

 @ResponseBody
    @RequestMapping("/topicSender")
    public String topicSender(@RequestParam("message")String message){
        String opt="";
        try {
            String[] severities={"error","info","warning"};
            String[] modules={"email","order","user"};
            for(int i=0;i<severities.length;i++){
                for(int j=0;j<modules.length;j++){
                    String routeKey = severities[i]+"."+modules[j];
                    String str = "the message is [rk:"+routeKey+"]["+message+"]";
                    rabbitTemplate.send("topic-exchange",routeKey,
                     new Message(str.getBytes(),new MessageProperties()));
                   }
                }
            opt = "suc";
        } catch (Exception e) {
            opt = e.getCause().toString();
        }
        return opt;
    }
  1. 消费者
    菜> spring配置文件和生产者其实差不多,可能差点的就是需要配置监听容器 ,生产者和消费者是根据路由键匹配的,只有路由键匹配才能接收到生产者的消息。

思路: 1. 配置连接工厂(与原生实现一样) —> 2. 配置spring的admin —> 3.创建队列 —> 4.创建交换器,并绑定队列 ,topic声明匹配模式(pattern) —>设置监听容器 。
监听容器类必须实现MessageListener类

<!-- rabbitMQ配置 -->
	<bean id="rabbitConnectionFactory"
		  class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
		<constructor-arg value="127.0.0.1"/>
		<property name="username" value="guest"/>
		<property name="password" value="guest"/>
		<property name="channelCacheSize" value="8"/>
		<property name="port" value="5672"></property>
	</bean>
	<rabbit:admin connection-factory="rabbitConnectionFactory"/>

    <!-- fanout交换器 begin-->
    <!-- 定义队列 -->
   <!--配置队列queue, Exchange, 以及将他们结合在一起的binding-->
    <!--在queue以及exchange中, 有一个重要的属性durable, 默认为true, 可以防止宕机后数据丢失。-->
    <!--在listener-container中, 有acknowledge属性, 默认为auto, 即消费者成功处理消息后必须有个应答, 如果消费者程序发生异常或者宕机, 消息会被重新放回队列-->
    
	<rabbit:queue name="h1_queue" durable="false"/>
	<rabbit:queue name="h2_queue" durable="false"/>
	<rabbit:queue name="h3_queue" durable="false"/>

    <!-- 把需要数据的队列与交换器绑定一起 -->
    <!--标准的AMQP Exchange有4种: Direct, Topic, Headers, Fanout, 根据实际需要选择。-->
    <!--Direct: 如果消息的routing key与bingding的routing key直接匹配的话, 消息将会路由到该队列上。-->
    <!--Topic: 如果消息的routing key与bingding的routing key符合通配符匹配的话, 消息将会路由到该队列上。-->
    <!--Headers: 如果消息参数表中的头信息和值都与binding参数表中相匹配, 消息将会路由到该队列上。-->
    <!--Fanout: 不管消息的routing key和参数表的头信息/值是什么, 消息将会路由到该队列上。-->
    
	<rabbit:fanout-exchange name="fanout-exchange"
							xmlns="http://www.springframework.org/schema/rabbit"
							durable="false">
		<rabbit:bindings>
			<rabbit:binding queue="h1_queue"></rabbit:binding>
			<rabbit:binding queue="h2_queue"></rabbit:binding>
			<rabbit:binding queue="h3_queue"></rabbit:binding>
		</rabbit:bindings>
	</rabbit:fanout-exchange>
    <!-- fanout交换器 end-->


    <!-- topic交换器 begin-->
    <!-- 定义队列 -->
    <rabbit:queue name="all_log_queue" durable="false"/>
    <rabbit:queue name="email_all_queue" durable="false"/>
    <rabbit:queue name="email_error_queue" durable="false"/>
    <rabbit:queue name="all_error_queue" durable="false"/>

    <!-- 把需要数据的队列通过路由键与交换器绑定一起 -->
    <rabbit:topic-exchange name="topic-exchange"
                           xmlns="http://www.springframework.org/schema/rabbit"
                           durable="false">
        <rabbit:bindings>
            <rabbit:binding queue="all_log_queue" pattern="#"></rabbit:binding>
            <rabbit:binding queue="email_all_queue" pattern="*.email"></rabbit:binding>
            <rabbit:binding queue="email_error_queue"  pattern="error.email"></rabbit:binding>
            <rabbit:binding queue="all_error_queue"  pattern="error.*"></rabbit:binding>

        </rabbit:bindings>
    </rabbit:topic-exchange>

    <!-- topic交换器 end-->


    <!--监听容器-->
      <!--  ref="fanoutService是bean监听实体类,在xml定义或注解并扫描包  -->
    <rabbit:listener-container connection-factory="rabbitConnectionFactory">
        <rabbit:listener ref="fanoutService_H1" queues="h1_queue" method="onMessage" />
        <rabbit:listener ref="fanoutService_H2" queues="h2_queue" method="onMessage" />
        <rabbit:listener ref="fanoutService_H3" queues="h3_queue" method="onMessage" />
        <rabbit:listener ref="allLogTopicService" queues="all_log_queue" method="onMessage" />
        <rabbit:listener ref="emailAllTopicService" queues="email_all_queue" method="onMessage" />
        <rabbit:listener ref="emailErrorTopicService" queues="email_error_queue" method="onMessage" />v
        <rabbit:listener ref="allErrorTopicService" queues="all_error_queue" method="onMessage" />
    </rabbit:listener-container>
@Component
public class AllLogTopicService implements MessageListener{
    private Logger logger = LoggerFactory.getLogger(AllLogTopicService.class);
    public void onMessage(Message message) {
        logger.info("Get message:"+new String(message.getBody()));
    }
}

猜你喜欢

转载自blog.csdn.net/pengjwhx/article/details/83550501