RabbitMQ消息中间件(三) RabbitMQ整合整合SpringAMQP

RabbitMQ整合Spring AMQP实践:

    RabbitAdmin:

        RabbitAdmin类可以很好的操作RabbitMQ,在Spring中直接进行注入即可,RabbitAdmin底层实现就是从Spring容器中获取Exchange,Bingding,RoutingKey以及Queue的@Bean声明,然后使用RabbitTemplate的execute方法执行对应的声明,修改,删除等一系列RabbitMQ基础功能操作。

       添加POM文件:

<dependency>
    <groupId>com.rabbit</groupId>
    <artifactId>amqp-client</artifactId>
    <version>3.6.5</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

        添加配置文件: 

@Configuration
@ComponentScan({"com.bfxy.spring.*"})
public class RabbitMQConfig{
    
    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses("192.168.11.76:5672");
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        connectionFactory.setVirtualHost("/");
        return connectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        //注意:autoStartup必须要设置为true,否则Spring容器不会加载RabbitAdmin类
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

/*--------------------@Bean注入模式使用-------------------*/
    /**
    *针对消费者配置
    *1.    设置交换机类型
    *2.    将队列绑定到交换机
    *  FanoutExchange:将消息分发到所有的绑定队列,无routingkey的概念
    *  HeadersExhchange:通过添加属性key-value匹配
    *  DirectExchange:按照routingkey分发到指定队列
    *  TopicExchange:多关键字匹配
    */
    @Bean
    public TopicExchange exchange(){
        return new TopicExchange("topic",true,false);
    }

    @Bean
    public Queue queue(){
        return new Queue("queue",true);
    }

    @Bean
    public Binding binding(){
        return BindingBuilder.bind(queue()).to(exchange()).with("spring.*");
    }

    @Bean
    public TopicExchange exchange(){
        return new TopicExchange("topic",true,false);
    }

}

         启动rabbitMQ服务,编写应用代码:

            rabbitmq-server start &

            lsof -i:5672

public static void main(){
    @Autowired
    private RabbitAdmin rabbitAdmin;

    public void admin()throws Exception{
        //声明交换机
        rabbitAdmin.declareExchange(new DirectExchange("test.direct",false,false));
        rabbitAdmin.declareExchange(new TopicExchange("test.topic",false,false));
        rabbitAdmin.declareExchange(new FanoutExchange("test.fanout",false,false));
        //声明队列
        rabbitAdmin.declareQueue(new Queue("test.direct.queue",false,false));
        rabbitAdmin.declareQueue(new Queue("test.topic.queue",false,false));
        rabbitAdmin.declareQueue(new Queue("test.fanout.queue",false,false));
        //设置绑定关系
        rabbitAdmin.declareBinding(new Binding("test.direct.queue",Binding.DestinationType.QUEUE,"test.direct","direct",new HashMap<>()));
        rabbitAdmin.declareBinding(BindingBuilder
                                .bind(new Queue("test.topic.queue",false))  //直接创建队列
                                .to(new TopicExchange("test.topic",false,false))  //直接创建交换机,建立关联关系
                                .with("user.#"));  //指定路由Key
    }
        rabbitAdmin.declareBinding(BindingBuilder
                                .bind(new Queue("test.fanout.queue",false))
                                .to(new FanoutExchange("test.fanout",false,false))
        //队列操作
        rabbitAdmin.purgeQueue("队列名",false); // 清空队列
    }
}

    RabbitTemplate:

        消息模板,与SpringAMQP整合时进行发送消息的关键类,该类提供了丰富的发送消息方法,包括可靠性投递消息方法,回调监听消息接口ConfirmCallback,返回值确认接口ReturnCallback等等。同样我们需要进行注入到Spring容器中,然后直接使用。

            添加配置文件: 

@Configuration
@ComponentScan({"com.bfxy.spring.*"})
public class RabbitMQConfig{
    
    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses("192.168.11.76:5672");
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        connectionFactory.setVirtualHost("/");
        return connectionFactory;
    }

                      /**具体队列信息在上个代码块**/

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        //注意:autoStartup必须要设置为true,否则Spring容器不会加载RabbitAdmin类
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }
}

            编写测试类:

public static void main(){
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void SendMessage() throws Rxception{
        //创建消息
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.getHeahers().put("key","value");
        Message message = new Message("Hello Wolrd".getBytes(),messageProperties);
        //发送
        rabbitTemplate.convertAndSend("topic","spring.*",message,new MessagePostProcessor(){
            @Override
            public Message postProcessMessage(Message message) throws AmqpException{
                System.err.println("-------添加额外配置");
                message.getMessageProperties().getHeaders().put("desc","额外修改的信息描述");
                return message;
            }
        });
        rabbitTemplate.converAndSend("topic","rabbit.abc","hello world");
    }
}

    SimpleMessageListenerContainer:

        简单消息监听容器:

            这个类非常强大,可以对他进行很多设置,对于消费者的配置项,这个类都可以满足。

            设置事务特性,事务管理器,事务属性,事务容量(并发),是否开启事务,回滚消息等。

            设置消费者数量,最大最小数量,批量消费。

            设置消息确认和自动确认模式,是否重回队列,异常捕获handler函数。

            设置消费者标签生成策略,是否独占模式,消费者属性等。

            设置具体的监听器,消息转换器等。

            注意:SimpleMessageListenerContainer可以进行动态设置,比如在运行中的应用可以动态的修改其消费者数量的大小,接收消息的模式等。

@Configuration
@ComponentScan({"com.bfxy.spring.*"})
public class RabbitMQConfig{
    
    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses("192.168.11.76:5672");
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        connectionFactory.setVirtualHost("/");
        return connectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        //注意:autoStartup必须要设置为true,否则Spring容器不会加载RabbitAdmin类
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

                   /**具体队列信息在上个代码块**/

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }

    @Bean
    public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        //container可以监听多个队列
        container.setQueue(queue1(),queue2(),queue3());
        //设置消费者数量
        container.setConcirrentConsumers(1);
        container.setMaxConcirrentConsumers(5);
        //设置重回队列
        container.setDefaultRequeueRejected(false);
        //设置签收模式(自动签收)
        container.setAcknowledgeMode(AcknowledgeMode.AUTO);
        //创建消费策略
        container.setConsumerTagStrategy(new ConsumerTagStrategy(){
            @Override
            public String createConsumerTag(String queue){
                return queue+"-"+UUID.randomUUID().toString();
            }
        });
        //设置监听
        container.setMessageListener(new ChannelAwareMessageListener(){
            @Override
            public void onMessage(Message message,Channel channel) throws Exception{
                String msg = new String(message.getBody());
            }
        });
        return container;
    }
}

            SimpleMessageListenerContainer为什么可以动态感知配置变更?

    MessageListenerAdapter:

        消息监听适配器:

            defaultListenerMethod默认监听方法名称:用于设置监听方法名称。

            Delegate委托对象:实际真实的委托对象,用于处理消息。

            queueOrTagToMenthodName:队列标识与方法名称组成的集合

            可以一一进行队列与方法名称的匹配。

            队列和方法名称绑定,即指定队列里的消息会被绑定的方法所接收处理。

@Configuration
@ComponentScan({"com.bfxy.spring.*"})
public class RabbitMQConfig{
    
    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses("192.168.11.76:5672");
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        connectionFactory.setVirtualHost("/");
        return connectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        //注意:autoStartup必须要设置为true,否则Spring容器不会加载RabbitAdmin类
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

                   /**具体队列信息在上个代码块**/

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }

    @Bean
    public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory){
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        //container可以监听多个队列
        container.setQueue(queue1(),queue2(),queue3());
        //设置消费者数量
        container.setConcirrentConsumers(1);
        container.setMaxConcirrentConsumers(5);
        //设置重回队列
        container.setDefaultRequeueRejected(false);
        //设置签收模式(自动签收)
        container.setAcknowledgeMode(AcknowledgeMode.AUTO);
        //创建消费策略
        container.setConsumerTagStrategy(new ConsumerTagStrategy(){
            @Override
            public String createConsumerTag(String queue){
                return queue+"-"+UUID.randomUUID().toString();
            }
        });

        //适配器方式:队列名称和方法名称也可以进行一一的匹配
        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        Map<String,String> queueOrTagToMethodName = new HashMap<>();
        queueOrTagToMethodName.put("queue1","method1");
        adapter.setDefaultListenerMethod("consumeMessage");
        container.setMessageListener(adapter);
        return container;
    }
}

/**
*  需和下面的MessageConverter配合使用
*/
public class MessageDelegate{
    //默认方法
    public void handleMessage(byte[] messageBody){
        System.err.printLn("默认方法,消息内容":+new String(messageBody));
    }
    //自定义方法1
    public void consumerMessage(byte[] messageBody){
        System.err.printLn("字节数组方法,消息内容":+new String(messageBody));
    }
    //自定义方法2
public void consumerMessage(byte[] messageBody){
        System.err.printLn("字符串方法,消息内容":+messageBody);
    }
}

    MessageConverter:

        消息转换器:

            我们进行发送消息的时候,正常情况下消息体分为二进制的数据方式进行传输,如果希望内部帮我们进行转换,或者指定自定义的转换器,就需要用到MessageConverter

            重写下面两个方法:

                1.toMessage:java对象转换为Message

                2.fromMessage:Message对象转换为java对象

            自定义常用转换器:MessageConverter,一般来讲都需要实现这个接口

public class TextMessageConverter implements MessageConverter{
    @Override
    public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException{
        return new Message(object.toString().getBytes(),messageProperties);
    }
    @Override
    public Object fromMessage(Message message) throws MessageConversionException{
        String contentType = message.getMessageProperties().getContentType();
        //消息包含Text的时候才能转换
        if(null != contentType && contentType.contains("text")){
            return new String(message.getBody());
        }
        return message.getBody();
    }
}

            Json转换器:Jackson2JsonMessageConverter:可以进行java对象的转换功能(支持java对象转换):

            DefaultJackson2JavaTypeMapper映射器:可以进行java对象的映射关系:

                config:

MessageListenerAdapeter adapter = new MessageListenerAdapter(new MesssageDelegate());
adapter.setDefaultListenerMethod("consumerMessage");
Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();

/*add java*/
DefaultJacksonvilleJavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper();
jackson2JsonMessageConverter.setJavaTypeMapper(javaTypeMapper);
/*finish*/

adapter.setMessageConverter(jackson2JsonMessageConverter);
container.setMessageListener(adapter);


/*支持java对象多映射转换*/
MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
adapter.setDafaultListenerMethod("consumeMessage");
Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper();

Map<String,Class<?>> idClassMapping = new HashMap<String,Class<?>>();
idClassMapping.put("order",com.bfxy.spring.entity.Order.class);
idClassMapping.put("packaged",com.bfxy.spring.entity.Packaged.class);

javaTypeMapper.setIdClassMapping(idClassMapping);
jackson2JasonMessageConverter.setJavaTypeMapper(javaTypeMapper);
adapter.setMessageConverter(jackson2JsonMessageConverter);
container.setMessageListener(adapter);

                 MessageDelegate:

public class MessageDelegate{
    public void handleMessage(byte[] messageBody){
        System.err.printLn("map方法,消息内容":+messageBody);
    }
    public void consumerMessage(Order order){
        System.err.printLn("order对象,消息内容":+order.getId()+order.getName()+order.getContent());
    }
    public void consumerMessage(Packaged pack){
        System.err.printLn("order对象,消息内容":+pack.getId()+pack.getName()+pack.getContent());
    }
}

                 测试类:

public void sendMappingMessage() throws Exception{
    ObjectMapper mapper = new ObjectMapper();
    Order order = new Order();
    order.setId("001");
    oder.setName("订单消息");
    order.setContent("订单描述消息");

    String json = mapper.writeValueAsString(order);
    System.err.println(json);

    MessageProperties messageProperties = new MessageProperties();
    //注意一定要修改contentType为application/json
    messageProperties.setContentType("application/json");
    messageProperties.getHeaders().puy("__TypeId__","order");
    Message message = new Message(json.getBytes(),messageProperties);
    rabbitTemplate.send("topic","spring.order",message);

    Packaged pack = new Packaged();
    pack .setId("001");
    pack .setName("包裹消息");
    pack .setDescription("包裹描述消息");

    String json1 = mapper.writeValueAsString(order);
    System.err.println(json1);

    MessageProperties messageProperties1 = new MessageProperties();
    //注意一定要修改contentType为application/json
    messageProperties1.setContentType("application/json");
    messageProperties1.getHeaders().puy("__TypeId__","packaged");
    Message message1 = new Message(json1.getBytes(),messageProperties1);
    rabbitTemplate.send("topic","spring.order",message1);
}

            自定义二进制转换器:比如图片类型,PDF,PPT,流媒体

                config:

/**
* ext convert
*/
MessageListenerAdapter adapter = new MessageListenerAdapter();
adapter.setDafaultListenerMethod("consumerMessage");
//全局转换器:
ContentTypeDelegatingMessageConverter convert = new ContentTypeDelegatingMessageConverter();

TextMessageConverter textConverter = new TextMessageConverter();
convert.addDelegate("text",textConverter);
convert.addDelegate("html/text",textConverter);
convert.addDelegate("xml/text",textConverter);
convert.addDelegate("text/plain",textConverter);

Jackson2JsonMessageConverter jsonConvert = new Jackson2JsonMessageConverter();
convert.addDelegate("json",jsonConvert);
convert.addDelegate("application/json",jsonConvert);

ImageMessageConverter imageConverter = new ImageMessageConverter();
convert.addDelegate("image/png",imageConverter);
convert.addDelegate("image",imageConverter);

PDFMessageConverter pdfConverter = new PDFMessageConverter();
convert.addDelegate("application/pdf",pdfConverter );

adapter.setMessgeConverter(convert);
container.setMessageListener(adapter);

return container;

                 converter:

public class ImageMessageConverter implements MessageConverter{
    @Override
    public Message toMessage(Obejct object,MessageProperties messageProperties) throws MessageConverterException{
        throw new MessageConverterException("Error!");
    }

    @Override
    public Object fromMessage(Message message)throws MessageConverterException{
        sout("-------Image MessageConverter");
        
        Obejct _extName = message.getMessageProperties().getHeaders().get("extName");
        String extName = _extName ==null ? "png" :_extName.toString();
        
        byte[] body = message.getBody();
        String fileName = UUID.randomUUID().toString();
        String path = "c:/test/"+fileName+"."+extName;
        File f = new File(path);
        try{
            Files.copy(new ByteArrayInputStream(body),f.toPath());
        }catch (IOException e){
            e.printStackTrace();
        }
        return f;
    }
}

public class PDFMessageConverter implements MessageConverter{
    @Override
    public Message toMessage(Obejct object,MessageProperties messageProperties) throws MessageConverterException{
        throw new MessageConverterException("Error!");
    }

    @Override
    public Object fromMessage(Message message)throws MessageConverterException{
        sout("-------PDF MessageConverter");
        
        byte[] body = message.getBody();
        String fileName = UUID.randomUUID().toString();
        String path = "c:/test/"+fileName+"."+.pdf;
        File f = new File(path);
        try{
            Files.copy(new ByteArrayInputStream(body),f.toPath());
        }catch (IOException e){
            e.printStackTrace();
        }
        return f;
    }
}

                 测试类:

public static void main(){
    public void sendExtConverterMessage() throws Exception{
        //image
        byte[] body = new Files.readAllBytes(Paths.get("c:/text","picture.png"));
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setContentType("image/png");
        messageProperties.getHeaders().put("extName","png");
        Message message = new Message(body,messageProperties);
        rabbitTemplate.send("","image_queue",message);
        //pdf
        byte[] body = new Files.readAllBytes(Paths.get("c:/text","picture.png"));
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setContentType("applicatoin/pdf");
        Message message = new Message(body,messageProperties);
        rabbitTemplate.send("","image_queue",message);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值