zoukankan      html  css  js  c++  java
  • 【RabbitMQ消息中间件】10.Spring-Rabbit项目剖析

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://blog.csdn.net/u013517797/article/details/79601121
    之前我们详细介绍了RabbitMQ并且讲解了其5中队列模式,在期间编写了许多小例子。但是在真实的开发阶段,我们很少使用之前编写Demo时的编写方式,一个是不方便,一个是难以维护。所以,在企业级的开发中,一般是结合框架来进行开发的。

    一、spring-rabbit项目介绍
    在Java开发中,RabbitMQ的开发自然少不了与Spring框架的结合。本篇我们就来了解一下,Spring为我们提供的与RabbitMQ向结合的开源样例工程“Spring-Rabbit”,通过了解该开源工程,我们可以更加了解在实际开发中如何结合Spring来进行RabbitMQ业务的开发。

    在Spring的官方网站“spring.io”中,我们可以看到spring团队发布的与spring相关的历届以及最新的框架产品:

    而本此我们要了解的,就是spring框架对AMQP协议的支持,即是“spring AMQP”的相关产品:

    点击进去之后,可以看到该开源项目的详细介绍:

    可以在介绍中看到,该产品包含了两个部分,其中“spring-amqp”是一个基本的抽象实现,而“spring-rabbit”是一个基于RabbitMQ的一个具体实现。

    其实就是说,“spring-amqp”是所有符合消息队列协议产品的基础实现,而实现该基础的产品有很多,“spring-rabbit”就是其中一种。

    二、spring-rabbit使用
    首先我们在Eclipse中创建一个maven项目:

    然后编辑POM文件,添加spring核心依赖、日志相关依赖:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>cn.test.spring.rabbit</groupId>
    <artifactId>spring_rabbit_test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    
    <dependencies>
    <dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>3.4.1</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.7</version>
    </dependency>
    <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.3.2</version>
    </dependency>
    
    <dependency>
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-rabbit</artifactId>
    <version>1.4.0.RELEASE</version>
    </dependency> 
    
    <!-- spring核心依赖 -->
    <dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-core</artifactId> 
    <version>4.2.5.RELEASE</version> 
    </dependency>
    
    <dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-context</artifactId> 
    <version>4.2.5.RELEASE</version> 
    </dependency> 
    </dependencies>
    <build>
    <plugins>
    <plugin>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
    <version>3.0</version>
    </configuration>
    </plugin>
    </plugins>
    </build>
    </project>
    

      


    其中,spring-rabbit就是本次结合RabbitMQ的核心依赖jar,而amqp-client是rabbit通信的基础协议依赖。

    然后我们在maven工程的“src/main/resources”下创建日志配置文件“logj4.properties”:

    log4j.rootLogger=DEBUG,A1
    log4j.logger.com.jack = DEBUG
    log4j.logger.org.mybatis = DEBUG
    
    log4j.appender.A1=org.apache.log4j.ConsoleAppender
    log4j.appender.A1.layout=org.apache.log4j.PatternLayout
    log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
    

      

    下面是重点,在maven工程的“src/main/resources”下创建“rabbitmq-context,xml”来注入RabbitMQ需要的相关工厂类:
      
    在该配置

    <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/rabbit
    http://www.springframework.org/schema/rabbit/spring-rabbit-1.4.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
    
    <!-- 定义RabbitMQ的连接工厂 -->
    <rabbit:connection-factory id="connectionFactory"
    host="127.0.0.1" port="5672" username="jack" password="jack"
    virtual-host="/jack" />
    
    <!-- 定义Rabbit模板,指定连接工厂以及定义exchange -->
    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory" exchange="fanoutExchange" />
    <!-- 如果需要定义路由key,则需要添加routing-key参数指定路由key,如:routing-key="foo.bar" -->
    
    <!-- MQ的管理,包括队列、交换器等 -->
    <rabbit:admin connection-factory="connectionFactory" />
    
    <!-- 定义队列,自动声明 -->
    <rabbit:queue name="myQueue" auto-declare="true"/>
    
    <!-- 定义交换器,自动声明 -->
    <rabbit:fanout-exchange name="fanoutExchange" auto-declare="true">
    <rabbit:bindings>
    <rabbit:binding queue="myQueue"/>
    </rabbit:bindings>
    </rabbit:fanout-exchange>
    <!-- 如果交换机为通配符类型,则需要在队列中定义通配符的key(pattern),如:pattern="foo.*" -->
    
    <!-- 队列监听 -->
    <rabbit:listener-container connection-factory="connectionFactory">
    <rabbit:listener ref="foo" method="listen" queue-names="myQueue" />
    </rabbit:listener-container>
    
    <bean id="foo" class="cn.jack.rabbitmq.spring.Foo" />
    
    </beans>
    

      

    文件中,首先定义了RabbitMQ的连接工厂:

    <!-- 定义RabbitMQ的连接工厂 -->
    <rabbit:connection-factory id="connectionFactory"
    host="127.0.0.1" port="5672" username="jack" password="jack"
    virtual-host="/jack" />
    而该连接工厂做的事情,和之前我们自己编写的连接工厂做的事情是一样的:
    package cn.jack.rabbitmq.connection;
    import java.io.IOException;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.ConnectionFactory;
    
    public class ConnectionUtil {
    public static Connection getConnection() throws IOException{
    //定义连接工厂
    ConnectionFactory factory = new ConnectionFactory();
    //定义连接地址
    factory.setHost("localHost");
    //定义端口
    factory.setPort(5672);
    //设置账号信息,用户名、密码、vhost
    factory.setVirtualHost("/jack");
    factory.setUsername("jack");
    factory.setPassword("jack");
    // 通过工厂获取连接
    Connection connection = factory.newConnection();
    return connection;
    }
    }
    

      


    都是定义一些列连接信息后,通过工厂获取RabbitMQ的连接对象。

    然后下面的配置是定义Rabbit模板,指定连接工厂以及定义exchange(交换机):

    <!-- 定义Rabbit模板,指定连接工厂以及定义exchange -->
    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory" exchange="fanoutExchange" />
    

      


    该处做的事情,就是定义一个模板,指定其获取连接的连接工厂,和其绑定的交换机。
    如果是路由或通配符那种需要定义发送消息的路由key的交换机,则需要再添加一个“routing-key”参数来指定路由key:

    <!-- 如果需要定义路由key,则需要添加routing-key参数指定路由key -->
    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory"
    exchange="fanoutExchange" routing-key="foo.bar" />
    

      


    对于上面绑定的交换机,在下面有定义其详细配置:

    <!-- 定义交换器,自动声明 -->
    <rabbit:fanout-exchange name="fanoutExchange" auto-declare="true">
    <rabbit:bindings>
    <rabbit:binding queue="myQueue"/>
    </rabbit:bindings>
    </rabbit:fanout-exchange>
    

      


    其中auto-declare是指,是否进行自动声明,即是如果交换机不存在时,spring会帮助创建该交换机,如果交换机存在则忽略。在里面的“rabbit:bindings”中配置的即是与该交换机绑定的队列。
    有三种交换机类型“fanout-exchange”、“direct-exchange”以及“topic-exchange”,分别是“非路由交换机”、“路由交换机”以及“通配符交换机”,具体区别在之前的总结中已经介绍,这里不再赘述。
    上面的配置是“fanout-exchange”类型的交换机,如果需要其他类型的,按照不同的前缀进行指定。下面是通配符交换机的配置方式:

    <!-- 如果交换机为通配符类型,则需要在队列中定义通配符的key(pattern) -->
    <rabbit:topic-exchange name="myExchange">
    <rabbit:bindings>
    <rabbit:binding queue="myQueue" pattern="foo.*" />
    </rabbit:bindings>
    </rabbit:topic-exchange>
    

      


    首先将配置标签定义为“topic-exchange”,然后里面的队列要指定相关的key键,用以接收符合该key的消息。

    对于名为“myQueue”队列也在上面定义了,并且也配置了自动声明:

    <!-- 定义队列,自动声明 -->
    <rabbit:queue name="myQueue" auto-declare="true"/>
    

      


    在上面还有一个配置,是RabbitMQ的管理中心:

    <!-- MQ的管理,包括队列、交换器等 -->
    <rabbit:admin connection-factory="connectionFactory" />
    

      


    它的作用就是管理交换机和队列的,对于交换机和路由器上面设置的“auto-declare”自动声明,是由上面的MQ管理中心来做自动声明的工作的。

    上面所讲解的配置,其实已经完成了一个生产者所做的事情。那么最后就是配置消费者的相关设置,即是“队列监听”:

    <!-- 队列监听 -->
    <rabbit:listener-container connection-factory="connectionFactory">
    <rabbit:listener ref="foo" method="listen" queue-names="myQueue" />
    </rabbit:listener-container>
    
    <bean id="foo" class="cn.jack.rabbitmq.spring.Foo" />
    

      


    首先为队列监听配置一个连接工厂,然后在其中配置消费者的依赖id、执行监听的方法名以及接受消息的队列名称。

    对于rabbit:listener中的ref中的对象id,在下面有一个bean的配置,会将foo对象加载到spring的bean容器中。

    配置文件讲解完毕,我们基于该配置来创建一个生产者和消费者。
    在“src/mian/java”下创建一个SpringMain类,在其中创建一个mian方法,编写生产者的逻辑:

    package cn.jack.rabbitmq.spring;
    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.context.support.AbstractApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class SpringMain {
    public static void main(String[] args) throws Exception {
    AbstractApplicationContext ctx = new ClassPathXmlApplicationContext(
    "classpath:rabbitmq-context.xml");
    //Rabbit模板
    RabbitTemplate template = ctx.getBean(RabbitTemplate.class);
    //发送消息
    template.convertAndSend("Hello,world!");
    Thread.sleep(1000);//休眠1秒
    ctx.close();//关闭容器
    }
    }
    

      


    在该类中,首先使用ClassPathXmlApplicationContext获取xml配置的对象ctx,然后通过getBean获取“RabbitTemplate”类型的Rabbit模板,之后执行convertAndSend方法将消息发送至交换机或队列,最后执行ctx的close关闭容器。

    其实上面我们业务层需要关注的就是获取RabbitTemplate并发送消息,之前的ClassPathXmlApplicationContext获取xml配置对象的操作在一般的企业工程中是不会这样写的,一般会进行包扫描和自动注解注入的方式获取相关的bean,无需直接操作ClassPathXmlApplicationContext获取xml配置对象:
    消息发送类:

    package com.training.rabbitmq.sender; 
    import org.springframework.amqp.core.AmqpTemplate; 
    import org.springframework.beans.factory.annotation.Autowired; 
    import org.springframework.stereotype.Component; 
    
    @Component 
    public class DemoRabbitMqSender { 
    
    @Autowired 
    private AmqpTemplate rabbitTemplate; 
    
    public void send(String content) { 
    System.out.println("Sender : " + content); 
    this.rabbitTemplate.convertAndSend("hello", content); 
    } 
    
    } 
    

      


    消息接收类

    package com.training.rabbitmq.controller; 
    import io.swagger.annotations.ApiOperation; 
    import javax.servlet.http.HttpSession; 
    import org.springframework.beans.factory.annotation.Autowired; 
    import org.springframework.web.bind.annotation.RequestMapping; 
    import org.springframework.web.bind.annotation.RequestMethod; 
    import org.springframework.web.bind.annotation.ResponseBody; 
    import org.springframework.web.bind.annotation.RestController; 
    import com.training.core.dto.ResultDataDto; 
    import com.training.rabbitmq.sender.DemoRabbitMqSender; 
    
    @RestController 
    @RequestMapping(value="/rabbitmq") 
    public class DemoRabbitMqController { 
    
    @Autowired 
    private DemoRabbitMqSender demoRabbitMqSender; 
    
    /** 
    * 发送测试消息队列 
    */ 
    @ApiOperation(value="发送测试消息队列", notes="addEntity") 
    @RequestMapping(value = "/addRabbitMq", method = RequestMethod.GET) 
    public @ResponseBody ResultDataDto addEntity(HttpSession httpSession) { 
    demoRabbitMqSender.send("Hello,World!"); 
    return ResultDataDto.addAddSuccess(); 
    } 
    } 
    

      


    上面的代码仅供参考,不使用于本篇创建的样例工程,因为这里没有集成Spring的其它环境(核心/web/mvc等),仅仅为了方便演示rabbit的整合,所以直接使用了ClassPathXmlApplicationContext。

    对于消费者,它的编写就十分的简单。之前配置文件中配置了一个foo的bean:

    <bean id="foo" class="cn.jack.rabbitmq.spring.Foo" />
    

      


    所以我们下面在“src/mian/java”下创建cn.jack.rabbitmq.spring包下的Foo类:

    package cn.jack.rabbitmq.spring;
    public class Foo {
    //具体执行业务的方法
    public void listen(String foo){
    System.out.println("消费者:"+foo);
    }
    }
    

      


    代码十分简单,复杂的传输过程已经由spring通过配置文件的规则进行了处理。上面的listen方法即是在队列监听中配置的“method”参数:

    <!-- 队列监听 -->
    <rabbit:listener-container connection-factory="connectionFactory">
    <rabbit:listener ref="foo" method="listen" queue-names="myQueue" />
    </rabbit:listener-container>
    

      


    下面我们运行SpringMain类的main方法,可以在控制台看到如下信息:

    然后到RabbitMQ的管理工具中查看队列:

    可以看到创建了一个新的名为“MyQueue”的队列。
    至此,Spring与RabbitMQ结合的小样例工程编写完毕。

    后期将会编写一个结合Web工程的RabbitMQ与Spring结合的实例,到时将使用包扫描和注解的方式注入Rabbit模板的实现。

    转载请注明出处:http://blog.csdn.net/acmman/article/details/79601121
    ————————————————
    版权声明:本文为CSDN博主「光仔December」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/acmman/article/details/79601121

  • 相关阅读:
    JSAJAX请求
    ES6-形参默认值
    ES6-三点运算符
    ES6-箭头函数
    ES6-对象的简写方式
    ES6-使用模板字符串完成字符串拼接
    201712-2 游戏
    Product of Polynomials
    Maximum Subsequence Sum
    蓝桥杯 龟兔赛跑预测
  • 原文地址:https://www.cnblogs.com/laosunlaiye/p/11671597.html
Copyright © 2011-2022 走看看